基于Basys2的Booth乘法器的设计
目錄
一、設(shè)計(jì)指標(biāo)(老樣子,鯤鯤定的,我直接貼上來)
二、Booth乘法原理
三、Verilog代碼
1、Booth乘法器:
2、顯示轉(zhuǎn)換模塊:
3、數(shù)值位譯碼器:
4、符號(hào)位譯碼器:
5、時(shí)鐘分頻模塊:
6、數(shù)碼管動(dòng)態(tài)掃描模塊:
7、LED顯示模塊:
8、頂層模塊:
四、FPGA實(shí)現(xiàn):
1、管腳約束
?2、上板結(jié)果:
一、設(shè)計(jì)指標(biāo)(老樣子,鯤鯤定的,我直接貼上來)
在Basys2/3開發(fā)板上使用7段數(shù)碼管和SW0-SW7實(shí)現(xiàn)一個(gè)4位輸入的Booth乘法器,要求如下:
SW0-SW3輸入為乘數(shù),輸入數(shù)據(jù)格式為補(bǔ)碼;
SW0-SW3輸入為乘數(shù),輸入數(shù)據(jù)格式為補(bǔ)碼;
7段數(shù)碼管低2組作為加法器結(jié)果輸出,十六進(jìn)制格式輸出;
二、Booth乘法原理
Booth算法的顯著優(yōu)勢(shì)是直接對(duì)補(bǔ)碼進(jìn)行乘法運(yùn)算,其算法原理可以參考以下幾個(gè):(我不認(rèn)為我講的比他們更清楚,哈哈哈另一方面原因是我已經(jīng)忘記了):?
【FPGA基礎(chǔ)知識(shí)】booth算法:Verilog乘法原理與Booth算法優(yōu)化_嗶哩嗶哩_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算法之后,這個(gè)實(shí)驗(yàn)題就已經(jīng)解決了一大半了,剩下的就是用我們已經(jīng)講過的數(shù)碼管動(dòng)態(tài)掃描模塊將結(jié)果顯示出來了。
三、Verilog代碼
應(yīng)用模塊化的思想來進(jìn)行,系統(tǒng)框圖大概張這個(gè)樣子:
?結(jié)合題目要求,我打算用數(shù)碼管的后兩位以十六進(jìn)制補(bǔ)碼形式顯示運(yùn)算結(jié)果(4位*4位結(jié)果為8位,所以轉(zhuǎn)化為16進(jìn)制就是2位),用8個(gè)LED作為輸入的乘數(shù)和被乘數(shù)的顯示(亮為1,滅為0)
具體代碼如下:
1、Booth乘法器:
采用三段式狀態(tài)機(jī)的結(jié)構(gòu)來進(jìn)行Booth乘法運(yùn)算。輸入時(shí)鐘、復(fù)位、乘數(shù)、被乘數(shù),輸出結(jié)果到數(shù)碼管顯示模塊轉(zhuǎn)化為段選碼顯示在數(shù)碼管上。
module Booth_mul #(parameter DATA_WIDTH = 4) (input clk,input rst,input [DATA_WIDTH-1:0]num1_comp,//被乘數(shù)input [DATA_WIDTH-1:0]num2_comp,//乘數(shù)output reg [2*DATA_WIDTH-1:0]result// output Done );//狀態(tài)機(jī)方式實(shí)現(xiàn)Radix_2 Booth乘法器//狀態(tài)聲明(格雷碼)parameter IDLE = 2'b00;parameter ADD = 2'b01;parameter SHIFT = 2'b11;parameter OUTPUT = 2'b10;//內(nèi)部寄存器、信號(hào)線聲明reg [1:0]current_state;//寄存當(dāng)前狀態(tài)reg [1:0]next_state;//寄存下一狀態(tài)wire [DATA_WIDTH-1:0]num2_comp_neg;//乘數(shù)的補(bǔ)碼reg [DATA_WIDTH-1:0]iter_cnt;//控制迭代次數(shù)reg [2*DATA_WIDTH:0]p_reg;//P空間,用于右移reg [2*DATA_WIDTH:0]sum_reg;//暫存ADD操作之后的P空間數(shù)值assign num2_comp_neg = ~num2_comp + 1;//狀態(tài)轉(zhuǎn)移控制always@(posedge clk or posedge rst)beginif(rst)current_state <= IDLE;elsecurrent_state <= next_state;end//確定下一個(gè)狀態(tài)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乘法器算法實(shí)現(xiàn)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]};//加乘數(shù)的補(bǔ)碼2'b10: sum_reg <= {p_reg[8:5] + num2_comp_neg,p_reg[4:0]};//加乘數(shù)的負(fù)數(shù)的補(bǔ)碼default: sum_reg <= p_reg;//不執(zhí)行加操作endcaseiter_cnt <= iter_cnt + 1;// is_Done <= 1'b0;endSHIFT:beginp_reg <= {sum_reg[2*DATA_WIDTH],sum_reg[2*DATA_WIDTH:1]};//整體右移一位,符號(hào)拓展// is_Done <= 1'b0;endOUTPUT:beginresult <= p_reg[2*DATA_WIDTH:1];// is_Done <= 1'b1;endendcaseendend//輸出計(jì)算完成信號(hào)// assign Done = is_Done;endmodule2、顯示轉(zhuǎn)換模塊:
由于十六進(jìn)制補(bǔ)碼形式很難一眼看出結(jié)果的十進(jìn)制數(shù)值,于是我就加入了一個(gè)顯示轉(zhuǎn)換,將有符號(hào)十六進(jìn)制數(shù)轉(zhuǎn)換為無符號(hào)十六進(jìn)制數(shù)(如果被轉(zhuǎn)換的是負(fù)數(shù),就在轉(zhuǎn)換結(jié)果之前顯示一個(gè)符號(hào))
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);//聲明內(nèi)部信號(hào)wire mode_flag;//輸出模式標(biāo)志(1:無符號(hào)位十六進(jìn)制輸出,0:帶符號(hào)位十六進(jìn)制輸出),默認(rèn)十六進(jìn)制輸出wire sign_flag;//判斷輸入是否為負(fù)數(shù)wire [7:0]comp_reg;//用于計(jì)算負(fù)數(shù)的真值對(duì)應(yīng)的二進(jìn)制數(shù)//模式狀態(tài)控制assign mode_flag = conversion;assign sign_flag = hex_number[7];assign comp_reg = ~hex_number+ 1'b1;//輸出轉(zhuǎn)換always@(posedge clk or posedge rst)beginif(rst)beginL_bit <= 4'd0;H_bit <= 4'd0;Sign <= 4'd0;endelse if(mode_flag)//無符號(hào)位十六進(jìn)制輸出beginif(sign_flag)//負(fù)數(shù)處理beginL_bit <= comp_reg[3:0];H_bit <= comp_reg[7:4];Sign <= 1'b1;endelse//正數(shù)處理beginL_bit <= hex_number[3:0];H_bit <= hex_number[7:4];Sign <= 1'b0;endendelse//帶符號(hào)位十六進(jìn)制輸出beginL_bit <= hex_number[3:0];H_bit <= hex_number[7:4];Sign <= 1'b0;endendendmodule3、數(shù)值位譯碼器:
將2位十六進(jìn)制數(shù)轉(zhuǎn)化為共陽極數(shù)碼管段選碼,用于數(shù)碼管動(dòng)態(tài)掃描
module wei_encoder(input [3:0]hex_number,output reg [7:0]display_code);//將輸入的十六進(jìn)制代碼轉(zhuǎn)換為共陽極數(shù)碼管段選編碼并輸出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 endmodule4、符號(hào)位譯碼器:
如果是負(fù)數(shù),就譯碼為一個(gè)“-”負(fù)號(hào)顯示在數(shù)值位前面,如果是正數(shù),就不顯示
module sign_encoder(input Sign,output reg [7:0]display_code);always@(*)beginif(Sign)display_code = 8'hbf;//-elsedisplay_code = 8'hff;//無end endmodule5、時(shí)鐘分頻模塊:
將板子輸入的50MHz時(shí)鐘通過計(jì)數(shù)分頻的形式轉(zhuǎn)化為1KHz時(shí)鐘,用于動(dòng)態(tài)掃描
module clk_div(input clk,input rst,output reg clk_div);//輸入板子50MHz時(shí)鐘,輸出1KHz時(shí)鐘//計(jì)數(shù)分頻: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//輸出時(shí)鐘控制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 endmodule6、數(shù)碼管動(dòng)態(tài)掃描模塊:
輸入分頻后的1KHz時(shí)鐘和待輸出的段選碼,根據(jù)掃描計(jì)數(shù)器的狀態(tài)控制動(dòng)態(tài)掃描位選和段選
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);//將輸入的十六進(jìn)制代碼轉(zhuǎn)換為共陽極數(shù)碼管段選碼動(dòng)態(tài)掃描輸出reg [1:0]sel_cnt;//掃描計(jì)數(shù)器//動(dòng)態(tài)掃描//掃描計(jì)數(shù)器控制位選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//位選與段選對(duì)應(yīng)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;endendcaseendendendmodule7、LED顯示模塊:
顯示乘數(shù)和被乘數(shù)(高4位和低4位分別代表一個(gè)4位二進(jìn)制數(shù))
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 endmodule8、頂層模塊:
上面構(gòu)建了這么多模塊,終于要在頂層模塊中實(shí)例化連接了
module top(input clk,input rst,input conversion,//用于選擇輸出模式(帶符號(hào)十進(jìn)制輸出或十六進(jìn)制輸出)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);//聲明內(nèi)部信號(hào)wire clk_div;//1KHz時(shí)鐘用于驅(qū)動(dòng)數(shù)碼管動(dòng)態(tài)掃描wire [7:0]Output_number_1;//數(shù)碼管右一顯示輸出wire [7:0]Output_number_2;//數(shù)碼管右二顯示輸出wire [7:0]Output_number_3;//數(shù)碼管右三顯示輸出wire [7:0]result;//將乘法運(yùn)算結(jié)果傳輸給編碼模塊// wire Done;//乘法運(yùn)算完成信號(hào)wire [3:0]L_bit;//校正后的低四位用于轉(zhuǎn)換為段選碼wire [3:0]H_bit;//校正后的高四位用于轉(zhuǎn)換為段選碼wire Sign;//判斷十進(jìn)制輸出的符號(hào)//模塊實(shí)例化//Booth乘法器Booth_mul multiplier(.clk(clk),.rst(rst),.num1_comp(num1_comp),.num2_comp(num2_comp),.result(result)// .Done(Done));//乘法結(jié)果(8位帶符號(hào)二進(jìn)制數(shù))校正為高低兩位(4位二進(jìn)制數(shù))用于轉(zhuǎn)換為段選碼output_conversion converse(.clk(clk),.rst(rst),.conversion(conversion),.hex_number(result),.L_bit(L_bit),.H_bit(H_bit),.Sign(Sign));//將乘法器輸出的數(shù)字轉(zhuǎn)化為段選碼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時(shí)鐘分頻為1KHz時(shí)鐘用于數(shù)碼管動(dòng)態(tài)掃描clk_div divider(.clk(clk),.rst(rst),.clk_div(clk_div));//數(shù)碼管動(dòng)態(tài)掃描模塊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燈顯示輸入的補(bǔ)碼(亮:1,滅:0),方便觀察led_display led(.clk(clk),.rst(rst),.number_1(num1_comp),.number_2(num2_comp),.led(led_light)); endmodule四、FPGA實(shí)現(xiàn):
1、管腳約束
老樣子,根據(jù)開發(fā)板手冊(cè)在PlanAhead上進(jìn)行綁定
生成的約束文件如下:
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、上板結(jié)果:
4’h7 * 4’h8 = 8’hC8,同時(shí)驗(yàn)證結(jié)果補(bǔ)碼與源碼轉(zhuǎn)換
?
?4’h7 * 4’h7 = 8’h31
?4’h7 * 4’h3 = 8’h15
?
總結(jié)
以上是生活随笔為你收集整理的基于Basys2的Booth乘法器的设计的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小程序tab选项卡请求我的订单数据筛选处
- 下一篇: Android手机GPS卫星定位与通过W