FPGA课设-基于Xilinx Basys2开发板的除法器设计
Posted jeavenwong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FPGA课设-基于Xilinx Basys2开发板的除法器设计相关的知识,希望对你有一定的参考价值。
介绍一下Basys开发板:
Basys2 FPGA开发板是一个电路设计实现平台,任何人都可以通过它来搭建一个真正的数字电路。Basys2是围绕着一个Spartan-3E FPGA芯片和一个Atmel AT90USB USB控制器搭建的,它提供了完整、随时可以使用的硬件平台,并且它适合于从基本逻辑器件到复杂控制器件的各种主机电路.Basys2开发板兼容所有版本的Xilinx ISE工具,其中也包括免费的WebPack版本。Basys2附带一个用于供电和编程的USB下载线,所以就不需要其他供电器件或编程下载线。
此次课设实现的功能:
设计一个除法器,能在Basys2开发板上实际运行。
被除数为16位,除数为8位,被除数和除数都用按键输入,结果用数码管显示,设置一个使能开关,开关朝上拨时才进行运算。由于数码管和按键等资源数量较少,因此可以考虑采取下面的方案实现。
LD2 LD1 LD0指示状态,000是起始状态,001用于输入被除数高8位,010用于输入被除数低8位,011用于输入除数(8位),100用于显示结果,101用于显示被除数和除数
btn1和btn0和数码管配合,用于改变准备输入的数据
btn2用于将数码管显示的数据输入到相应的地方,同时切换状态。btn3 的功能也是切换状态,如果用btn3切换状态,则不改变原来的数据。
sw6如果为1表示允许进行除法运算,为0则表示不允许。
因为LD2-LD0为100和101时需要显示6位16进制数,而数码管只有4个,所以用sw7进行切换。LD2-LD0为100时,sw7为0时显示商,为1时显示余数,LD2-LD0为101时,sw7为0时显示被除数,为1时显示除数。
设计一个除法器,能在Basys2开发板上实际运行。
被除数为16位,除数为8位,被除数和除数都用按键输入,结果用数码管显示,设置一个使能开关,开关朝上拨时才进行运算。由于数码管和按键等资源数量较少,因此可以考虑采取下面的方案实现。
使用2个开关决定状态,例如SW1和SW0,SW1-SW0为00时用于输入被除数,通过4个按键输入4位16进制数,输入的数通过数码管显示;01时用于输入除数,通过2个按键输入2位16进制数,输入的数通过数码管显示;10时显示商;11时显示余数。
上代码:
顶层模块chufaqi.v:
1 module chufaqi(reset,en,clk,sw1,sw0,btn3,btn2,btn1,btn0,an0,an1,an2,an3, 2 dp,cg,cf,ce,cd,cc,cb,ca); //除法器顶层模块chufaqi,端口名列表 3 //端口的申明 4 input reset,clk,sw1,sw0,btn3,btn2,btn1,btn0; 5 output an0,an1,an2,an3,dp,cg,cf,ce,cd,cc,cb,ca; 6 input en; 7 8 //四个待显示的数据 9 reg[3:0] disp_data0,disp_data1,disp_data2,disp_data3; 10 //16位被除数 11 wire[15:0] dividend; 12 //8位除数 13 wire[7:0] divisor; 14 //16位商 15 wire[15:0] res; 16 //8位余数 17 wire[7:0] rm; 18 //输入被除数时存放按键状态的寄存器 19 reg dividend_key0,dividend_key1,dividend_key2,dividend_key3; 20 //除数输入的时候存放按键状态寄存器 21 reg divisor_key0,divisor_key1; 22 23 always@(*) //任何被赋值变量发生变化时执行 24 begin 25 if({sw1,sw0}==2\'b00) //开关sw1和sw0关闭 26 begin 27 dividend_key0<=btn0; //被除数的按键输入 28 dividend_key1<=btn1; 29 dividend_key2<=btn2; 30 dividend_key3<=btn3; 31 end 32 else 33 begin 34 dividend_key0<=1\'b0; //当开关sw1和sw0不是都关闭的时候,把所有的按键状态都清0 35 dividend_key1<=1\'b0; 36 dividend_key2<=1\'b0; 37 dividend_key3<=1\'b0; 38 end 39 end 40 41 always@(*) 42 begin 43 if({sw1,sw0}==2\'b01) //开关sw1关闭,并且sw0打开的时候,进行除数的输入 44 begin 45 divisor_key0<=btn0; //除数的按键输入 46 divisor_key1<=btn1; 47 end 48 else 49 begin 50 divisor_key0<=1\'b0; //当不是开关sw1关闭,并且sw0打开的时候,把所有的按键状态都清0 51 divisor_key1<=1\'b0; 52 end 53 end 54 55 always@(*) //任何被赋值变量发生变化时都会执行 56 begin 57 case({sw1,sw0}) //根据sw1和sw0的状态来选择不同的数进行显示 58 2\'b00: //sw1=0,sw0=0的时候,显示被除数 59 begin 60 disp_data0<=dividend[3:0]; //把被除数的0到3位放在寄存器disp_data0中,在数码管模块中显示 61 disp_data1<=dividend[7:4]; //把被除数的4到7位放在寄存器disp_data1中,在数码管模块中显示 62 disp_data2<=dividend[11:8]; //把被除数的8到11位放在寄存器disp_data2中,在数码管模块中显示 63 disp_data3<=dividend[15:12]; //把被除数的12到15位放在寄存器disp_data3中,在数码管模块中显示 64 end 65 2\'b01: //sw1=0,sw0=1的时候,显示除数 66 begin 67 disp_data0<=divisor[3:0]; //把除数的0到3位放在寄存器disp_data0中,在数码管模块中显示 68 disp_data1<=divisor[7:4]; //把被除数的4到7位放在寄存器disp_data1中,在数码管模块中显示 69 disp_data2<=4\'b0000; //把disp_data2和disp_data3赋值为0,即把左边的两个数码管均显示为0 70 disp_data3<=4\'b0000; 71 end 72 2\'b10: //sw1=1,sw0=0的时候,显示商 73 begin 74 disp_data0<=res[3:0]; //把商的0到3位放在寄存器disp_data0中,在数码管模块中显示 75 disp_data1<=res[7:4]; //把商的4到7位放在寄存器disp_data1中,在数码管模块中显示 76 disp_data2<=res[11:8]; //把商的8到11位放在寄存器disp_data2中,在数码管模块中显示 77 disp_data3<=res[15:12]; //把商的12到15位放在寄存器disp_data3中,在数码管模块中显示 78 end 79 2\'b11: //sw1=1,sw0=1的时候,显示余数 80 begin 81 disp_data0<=rm[3:0]; //把余数的0到3位放在寄存器disp_data0中,在数码管模块中显示 82 disp_data1<=rm[7:4]; //把余数的4到8位放在寄存器disp_data1中,在数码管模块中显示 83 disp_data2<=4\'b0000; //把disp_data2和disp_data3赋值为0,即把左边的两个数码管均显示为0 84 disp_data3<=4\'b0000; 85 end 86 endcase 87 end 88 89 //调用除法器模块 90 91 division u1(.reset(reset),.en(en),.clk(clk),.num(dividend),.den(divisor),.res(res),.rm(rm)); 92 93 //调用数码管显示模块 94 95 shumaguan u2(.clk(clk),.reset(reset),.datain0(disp_data0),.datain1(disp_data1), 96 .datain2(disp_data2),.datain3(disp_data3), 97 .an0(an0),.an1(an1),.an2(an2),.an3(an3), 98 .dp(dp),.cg(cg),.cf(cf),.ce(ce),.cd(cd),.cc(cc),.cb(cb),.ca(ca)); 99 100 101 //下面调用按键计数模块,分别对被除数的输入和除数的输入的时候的按键次数进行计数 102 //输入被除数的第一位数,即dividend[3:0] 103 key_count u3(.reset(reset),.clk(clk),.key(dividend_key0),.q(dividend[3:0])); 104 //输入被除数的第二位数,即dividend[7:4] 105 key_count u4(.reset(reset),.clk(clk),.key(dividend_key1),.q(dividend[7:4])); 106 //输入被除数的第三位数,即dividend[11:8] 107 key_count u5(.reset(reset),.clk(clk),.key(dividend_key2),.q(dividend[11:8])); 108 //输入被除数的第四位数,即dividend[15:12] 109 key_count u6(.reset(reset),.clk(clk),.key(dividend_key3),.q(dividend[15:12])); 110 //输入除数的第一位数,即divisor[3:0] 111 key_count u7(.reset(reset),.clk(clk),.key(divisor_key0),.q(divisor[3:0])); 112 //输入除数的第二位数,即divisor[7:4] 113 key_count u8(.reset(reset),.clk(clk),.key(divisor_key1),.q(divisor[7:4])); 114 115 endmodule
除法器模块division.v
1 module division(reset,en,clk,num,den,res,rm); //除法器模块 2 //端口申明 3 input reset,en,clk; 4 input[15:0] num; //被除数 5 input[7:0] den; //除数 6 output[15:0] res; //商 7 output[7:0] rm; //余数 8 9 reg[15:0] res; 10 reg[7:0] rm; 11 12 //用tbuf寄存器来存放被除数,用dbuf寄存器来存放除数 13 (*keep="true"*)reg[8:0] dbuf=9\'d0; //(*keep="true"*)保证在综合优化的时候不会被剪切掉 14 reg[23:0] tbuf=24\'d0; //tbuf初始化 15 16 reg[4:0] state; //定义状态寄存器 17 18 always@(posedge reset or posedge clk) //在复位信号的上升沿或者时钟信号的上升沿执行 19 begin 20 if(reset) //复位 21 begin 22 res<=16\'d0; //商清零 23 rm<=8\'b0000_0000; //余数清零 24 state<=5\'b00000; //状态清零 25 end 26 else 27 begin 28 if(en) //使能信号,出发允许信号 29 begin 30 case(state) //状态机,根据state的不同状态进行不同的操作,这里用状态机进行16次的循环 31 0: 32 begin 33 tbuf[23:16]<= 8\'b0000_0000; //tbuf的高8位全补0 34 tbuf[15:0] <= num; //tbuf的低16位放被除数 35 dbuf<={1\'b0,den}; //dbuf最高位放0,低8位放除数 36 res<=tbuf[15:0]; //最终结果是:tbuf的低16位就是商 37 rm<=tbuf[23:16]; //tbuf的高8位就是余数 38 state<=state+1\'b1; //状态变量增加1 39 end 40 default: //当state!=5\'b00000时执行default 41 begin 42 if(tbuf[23:15]>=dbuf[8:0]) //判断比较tbuf高9位和dbuf的大小,相当于对被除数的最高的一位进行除法。满足条件执行下面的代码。 43 begin 44 tbuf[23:16]<=tbuf[22:15]-dbuf[7:0]; //对被除数此时的位数减去除数得到这一步的余数,再把余数存放到tbuf的高8位。 45 tbuf[15:0]<={tbuf[14:0],1\'b1}; //把等待除法操作的被除数的最高位放在tnuf的第15为上,之后一直进行上述的操作。 46 end 47 else 48 49 tbuf <= (tbuf << 1); //另一种写法:tbuf<={tbuf[22:0],1\'b0}; 即将tbuf向左移一位。就是当tbuf[23:15]<dbuf[8:0]时,此时商是0,余数为此时的被除数的位数,把商放在tbuf最后,即向左移一位。 50 51 if(state!=5\'b10000) //对未使用的state不断加1,回到0000-1111的状态,跳过未使用的state的状态 52 state<=state+1\'b1; 53 else 54 state<=5\'b00000; //回到state=5\'b00000的状态,显示商和余数 55 end 56 endcase 57 end 58 end 59 end 60 61 endmodule 62 //所以总的来说,此除法器的原理:就是移位 加上 减法。
按键计数模块key_count.v
1 module key_count(reset,clk,key,q); //按键计数模块 2 3 //端口的申明 4 input reset,clk,key; 5 output[3:0] q; 6 7 //寄存器q 8 reg[3:0] q; 9 10 //保持按键持续状态的寄存器 11 reg key_last; 12 13 //定按键次数增加的标志位rise_get 14 reg rise_get=1\'b0; 15 16 always @(posedge reset or posedge clk) //时钟上升沿或者复位信号的上升沿执行 17 begin 18 if(reset) //复位 19 key_last<=1\'b0; //清零 20 else 21 key_last<=key; //否则把按键的状态存放在寄存器key_last中 22 end 23 24 always @(posedge reset or posedge clk) //时钟上升沿或者复位信号的上升沿执行 25 begin 26 if(reset) //检测到reset为高电平的时候,即复位的时候 27 rise_get<=1\'b0; //将rise_get清零 28 else if((!key_last)&&key) 29 rise_get<=1\'b1; //当key_last=0并且key=1的时候,令按键增加标志rise_get=1。这行代码可以防止按键一直按下,按键一直按下的时候不会对按键计数 30 else //否则把rise_get清零 31 rise_get<=1\'b0; 32 end 33 34 always @(posedge reset or posedge clk) //时钟上升沿或者复位信号的上升沿执行 35 begin 36 if(reset) 37 q<=4\'b0000; //复位清零 38 else if(rise_get) //如果按键增加标志rise_get=1的时候按键次数加一 39 q<=q+1\'b1; 40 end 41 42 endmodule
数码管显示模块shumaguan.v
1 module shumaguan(clk,reset,datain0,datain1,datain2,datain3,an0,an1,an2,an3,dp,cg,cf,ce,cd,cc,cb,ca); //数码管显示模块 2 //端口的申明 3 input clk,reset; 4 input[3:0] datain0,datain1,datain2,datain3; 5 output an0,an1,an2,an3; 6 output dp,cg,cf,ce,cd,cc,cb,ca; 7 reg an0,an1,an2,an3; //输出数码管的选通信号 8 reg cg,cf,ce,cd,cc,cb,ca; //输出数码管的“七段” 9 10 wire dp; //数码管的“点” 11 12 reg div1000,div100; 13 reg[9:0] div1000_count; //定义一个10位的计数器 14 reg[6:0] div100_count; //定义一个7位的计数器 15 reg[1:0] state; //四种状态 16 reg[3:0] data; //0~F 需要显示的值,某一位数码管显示的数字 17 18 19 //计数器用来分频,用于显示数码管 20 always @(posedge clk or posedge reset) //在时钟的上升沿或者复位信号的上升沿的时候执行 21 begin 22 if(reset) //复位的时候 23 begin 24 div1000_count<=10\'d0; //把计数器清零 25 div1000<=1\'b0; //把计数的标志位清零 26 end 27 else if(div1000_count==10\'d999) //当计数器计数到999的时候 28 begin 29 div1000_count<=10\'d0; //div1000_count范围0~999 上一个上升沿div1000计数达到999 这个上升沿返回0 30 div1000<=1\'b1; //计数满1000 输出标志1 31 end 32 else 33 begin 34 div1000_count<=div1000_count+1\'b1; //当计数器div1000_count没有达到999的时候,每次时钟上升沿的时候计数器加一 35 div1000<=1\'b0; //并且保证此时的计数“满”的标志为0 36 end 37 end 38 39 always @(posedge clk or posedge reset) //在时钟的上升沿或者复位信号的上升沿的时候执行 40 begin 41 if(reset) //复位 42 begin 43 div100_count<=7\'b000_0000; //将计数器div100_count清零 44 div100<=1\'b0; //将计数器的标志位div100清零 45 end 46 else //未复位的时候 47 begin 48 if(div1000) //当计数器div1000_count满999的时候,标志位div1000会被置1 49 begin 50 if(div100_count==7\'d99) 51 begin 52 div100_count<=7\'b000_0000; //如果计数器div100_count计数满99的时候将计数器div100_count清零 53 //div100<=1\'b1; 54 end 55 else 56 begin 57 div100_count<=div100_count+1\'b1; //如果计数器div100_count计数不满99的时候将计数器div100_count加一 58 //div100<=1\'b0; 59 end 60 end 61 if((div1000)&&(div100_count==7\'d99)) //当计数器div100_count满99并且计数器div1000_count满999的时候将标志位div100置1 62 div100<=1\'b1; 63 else 64 div100<=1\'b0; 65 66 end 67 以上是关于FPGA课设-基于Xilinx Basys2开发板的除法器设计的主要内容,如果未能解决你的问题,请参考以下文章Xilinx FPGA开发板里的BRAM,对于小设计一般怎么使用
信迈TI OMAP-L138(定点/浮点DSP C674x+ARM9) + Xilinx Spartan-6 FPGA开发板规格书