前言
本次主要介绍一下关于EDA的实验:最大公约数,包括两个四位二进制整数以及两个八位二进制整数的最大公约数。
一、设计内容及原理
FPGA 不仅能够实现数字电路设计,而且能够完成算法设计。
(1)基础任务:输入两个四位二进制整数,找出他们的最大公约数,输入由拨码开关给入,输出由发光二极管显示。
(2)提高任务:由拨码开关输入两个八位二进制整数,找出两个输入数值的最大公约数,用数码管显示输入输出数值。
二、设计过程(及设计步骤)
2.1 基础任务
(1)源程序:
module decode(x,y,gcd);
input wire [3:0] x;
input wire [3:0] y;
output reg [3:0] gcd;
reg [3:0] xs,ys;
integer n;
always@(x or y)
begin
xs=x;
ys=y;
for(n=0;n<15;n=n+1)
begin
if(xs==ys)
xs=xs;
else if(xs<ys)
ys=ys-xs;
else
xs=xs-ys;
gcd=xs;
end
end
endmodule
(2)约束程序:
set_property -dict {PACKAGE_PIN K2 IOSTANDARD LVCMOS33} [get_ports {gcd[0]}]
set_property -dict {PACKAGE_PIN J2 IOSTANDARD LVCMOS33} [get_ports {gcd[1]}]
set_property -dict {PACKAGE_PIN J3 IOSTANDARD LVCMOS33} [get_ports {gcd[2]}]
set_property -dict {PACKAGE_PIN H4 IOSTANDARD LVCMOS33} [get_ports {gcd[3]}]
set_property -dict {PACKAGE_PIN R1 IOSTANDARD LVCMOS33} [get_ports {y[0]}]
set_property -dict {PACKAGE_PIN N4 IOSTANDARD LVCMOS33} [get_ports {y[1]}]
set_property -dict {PACKAGE_PIN M4 IOSTANDARD LVCMOS33} [get_ports {y[2]}]
set_property -dict {PACKAGE_PIN R2 IOSTANDARD LVCMOS33} [get_ports {y[3]}]
set_property -dict {PACKAGE_PIN P2 IOSTANDARD LVCMOS33} [get_ports {x[0]}]
set_property -dict {PACKAGE_PIN P3 IOSTANDARD LVCMOS33} [get_ports {x[1]}]
set_property -dict {PACKAGE_PIN P4 IOSTANDARD LVCMOS33} [get_ports {x[2]}]
set_property -dict {PACKAGE_PIN P5 IOSTANDARD LVCMOS33} [get_ports {x[3]}]
2.2 提高任务
(1)源程序:
module decode(x,y,led_pin,clk,rst_n,b,an); //声明模块名,端口信号
input clk; //时钟
input rst_n; //清零端
input wire [7:0] x; //输入的8位二进制数x
input wire [7:0] y; //输入的8位二进制数 y
output reg [15:0] led_pin; //输出的最大公约数
output reg [7:0] b; //段信号
output reg [3:0] an; //位选信号
reg [3:0] one,ten;
reg [1:0] hun;
reg [3:0] count;
reg [17:0]shift_reg=18'b000000000000000000;
reg [7:0] xs,ys;
reg [7:0] bin;
integer n;
always@(x or y)
begin
xs=x;
ys=y;
for(n=0;n<128;n=n+1)
begin
if(xs==ys)
xs=xs;
else if(xs<ys)
ys=ys-xs;
else
xs=xs-ys;
bin=xs;
end
end
always @ ( posedge clk or negedge rst_n ) // 计数部分
begin
if( !rst_n )
count<=0;
else if (count==9)
count<=0;
else
count<=count+1;
end
always @ (posedge clk or negedge rst_n ) // 二进制转换为十进制
begin
if (!rst_n)
shift_reg=0;
else if (count==0)
shift_reg={10'b0000000000,bin};
else if ( count<=8) //实现8次移位操作
begin
if(shift_reg[11:8]>=5) //判断个位是否>5,如果是则+3
begin
if(shift_reg[15:12]>=5) //判断十位是否>5,如果是则+3
begin
shift_reg[15:12]=shift_reg[15:12]+2'b11;
shift_reg[11:8]=shift_reg[11:8]+2'b11;
shift_reg=shift_reg<<1; //对个位和十位操作结束后,整体左移
end
else
begin
shift_reg[15:12]=shift_reg[15:12];
shift_reg[11:8]=shift_reg[11:8]+2'b11;
shift_reg=shift_reg<<1;
end
end
else
begin
if(shift_reg[15:12]>=5)
begin
shift_reg[15:12]=shift_reg[15:12]+2'b11;
shift_reg[11:8]=shift_reg[11:8];
shift_reg=shift_reg<<1;
end
else
begin
shift_reg[15:12]=shift_reg[15:12];
shift_reg[11:8]=shift_reg[11:8];
shift_reg=shift_reg<<1;
end
end
end
end
always @ ( posedge clk or negedge rst_n )
begin
if ( !rst_n )
begin
one<=0;
ten<=0;
hun<=0;
end
else if (count==9) //此时8次移位全部完成,将对应的值分别赋给个,十,百位
begin
led_pin[15:10]<=6'b000000;
led_pin[9:0]<=shift_reg[17:8];
end
end
reg [20:0] clkdiv; //时钟分频 计数器
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
clkdiv<=21'd0;
else
clkdiv<=clkdiv+1;
end
wire [1:0]bitcnt;
assign bitcnt=clkdiv[20:19];
always @(posedge clk or negedge rst_n) //an:位选信号产生,高有效
begin
if(!rst_n)
an=4'd0;
else
case(bitcnt)
2'd0:an=4'b0001;
2'd1:an=4'b0010;
2'd2:an=4'b0100;
2'd3:an=4'b1000;
endcase
end
reg [3:0]digit; //it 当前带显示的数字
always @(posedge clk or negedge rst_n)
begin
if (!rst_n)
digit=4'd0;
else
case(bitcnt)
2'd0:digit=led_pin[3:0];
2'd1:digit=led_pin[7:4];
2'd2:digit=led_pin[11:8];
2'd3:digit=led_pin[15:12];
default:digit=4'd0;
endcase
end
//b: 段码信号,共阴极数码管,段码高有效。 7段译码表
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
b=8'b11111100;
else
case(digit)
0:b=8'b11111100;
1:b=8'b01100000;
2:b=8'b11011010;
3:b=8'b11110010;
4:b=8'b01100110;
5:b=8'b10110110;
6:b=8'b10111110;
7:b=8'b11100000;
8:b=8'b11111110;
9:b=8'b11110110;
default:b=8'b11111100;
endcase
end
endmodule
(2)约束程序:
##按键
set_property -dict {PACKAGE_PIN B4 IOSTANDARD LVCMOS33} [get_ports {b[7]}]
set_property -dict {PACKAGE_PIN A4 IOSTANDARD LVCMOS33} [get_ports {b[6]}]
set_property -dict {PACKAGE_PIN A3 IOSTANDARD LVCMOS33} [get_ports {b[5]}]
set_property -dict {PACKAGE_PIN B1 IOSTANDARD LVCMOS33} [get_ports {b[4]}]
set_property -dict {PACKAGE_PIN A1 IOSTANDARD LVCMOS33} [get_ports {b[3]}]
set_property -dict {PACKAGE_PIN B3 IOSTANDARD LVCMOS33} [get_ports {b[2]}]
set_property -dict {PACKAGE_PIN B2 IOSTANDARD LVCMOS33} [get_ports {b[1]}]
set_property -dict {PACKAGE_PIN D5 IOSTANDARD LVCMOS33} [get_ports {b[0]}]
set_property -dict {PACKAGE_PIN G2 IOSTANDARD LVCMOS33} [get_ports {an[3]}]
set_property -dict {PACKAGE_PIN C2 IOSTANDARD LVCMOS33} [get_ports {an[2]}]
set_property -dict {PACKAGE_PIN C1 IOSTANDARD LVCMOS33} [get_ports {an[1]}]
set_property -dict {PACKAGE_PIN H1 IOSTANDARD LVCMOS33} [get_ports {an[0]}]
set_property -dict {PACKAGE_PIN P17 IOSTANDARD LVCMOS33} [get_ports clk ]
set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports rst_n ]
set_property -dict {PACKAGE_PIN R1 IOSTANDARD LVCMOS33} [get_ports {y[0]}]
set_property -dict {PACKAGE_PIN N4 IOSTANDARD LVCMOS33} [get_ports {y[1]}]
set_property -dict {PACKAGE_PIN M4 IOSTANDARD LVCMOS33} [get_ports {y[2]}]
set_property -dict {PACKAGE_PIN R2 IOSTANDARD LVCMOS33} [get_ports {y[3]}]
set_property -dict {PACKAGE_PIN P2 IOSTANDARD LVCMOS33} [get_ports {y[4]}]
set_property -dict {PACKAGE_PIN P3 IOSTANDARD LVCMOS33} [get_ports {y[5]}]
set_property -dict {PACKAGE_PIN P4 IOSTANDARD LVCMOS33} [get_ports {y[6]}]
set_property -dict {PACKAGE_PIN P5 IOSTANDARD LVCMOS33} [get_ports {y[7]}]
set_property -dict {PACKAGE_PIN T5 IOSTANDARD LVCMOS33} [get_ports {x[0]}]
set_property -dict {PACKAGE_PIN T3 IOSTANDARD LVCMOS33} [get_ports {x[1]}]
set_property -dict {PACKAGE_PIN R3 IOSTANDARD LVCMOS33} [get_ports {x[2]}]
set_property -dict {PACKAGE_PIN V4 IOSTANDARD LVCMOS33} [get_ports {x[3]}]
set_property -dict {PACKAGE_PIN V5 IOSTANDARD LVCMOS33} [get_ports {x[4]}]
set_property -dict {PACKAGE_PIN V2 IOSTANDARD LVCMOS33} [get_ports {x[5]}]
set_property -dict {PACKAGE_PIN U2 IOSTANDARD LVCMOS33} [get_ports {x[6]}]
set_property -dict {PACKAGE_PIN U3 IOSTANDARD LVCMOS33} [get_ports {x[7]}]
三、 硬件验证
3.1 基础任务
当按键F6、G4、G3、J4时(前四位拨码开关),表示第一个四位二进制数;当按键H4、J3、J2、K2时(后四位拨码开关),表示第二个四位二进制数;4个LED表示二进制最大公约数。
例如:第一幅图中输入的两个二进制数均为1111,即15和15的最大公约数,为15,对应的led显示为1111。
第二幅图中输入的两个二进制数分别为0010和0100,即2和4的最大公约数,为2,对应的led显示为0010。
3.2 提高任务
当按键F6、G4、G3、J4、H4、J3、J2、K2时(前八位拨码开关),表示第一个八位二进制数;当按键时U3、U2、V2、V5、V4、R3、T3、T5(后八位拨码开关),表示第二个八位二进制数;前4个数码管显示十进制最大公约数。
例如:第一幅图中输入的两个二进制数分别为00000100和10000000,即128和8的最大公约数,为8,对应的数码管显示为8。
第二幅图中输入的两个二进制数分别为11111111和11111111,即255和255的最大公约数,为255,对应的数码管显示为255。
四、 问题解决
1.问题:基础部分知道用LED显示结果,但是数码管不知道该怎么去控制。
解决办法:在网上查阅后,发现首先需要将求出的结果转化为十进制,然后用数码管循环显示。
2.问题:Vivado 上的数码管编程和自己之前学的51单片机不同,一开始不知如何写源程序去调用。
解决办法:在进行编码转换器显示到数码管程序前,学习显示译码器部分内 容,通过参考7段数码管显示十进制数 12345678,来实现bcd码转换器在数码管上的显示
3.问题:源文件提示错误[Synth 8-3352] multi-driven net count[9] with 2nd driver pin’count_reg[9]/Q’。
解决办法:在网上查阅后,发现这个错误的原因是在多个always块中对同一个reg型寄存器赋值,后来我把两个always语句合并成了一个,就解决了问题。
4.问题:编写的约束文件总是显示到某一行有错误。
解决办法:编写的约束文件时我犯过几个错误,主要有三个地方需要注意:(1)约束文件的注释符和源文件不一样,应该用##,而不是//。(2)引脚间要注意有空格。(3)端口信号是一位时,不需要用{}。例如[get_ports {wei}]是错误的,应该写成[get_ports wei]。
5.问题:做基础任务时,编写源代码时,首先看到的书上的程序,书上用的是一个while语句来进行循环,但是仿真时会有错误。
解决办法:自己通过查阅资料,发现while的循环次数是无限的,仿真时无法构架电路。但是我们小组没有按照书上的程序进行顶层模块的调动,来实现求最大公约数。而是用了一个for循环,确定2个四位二进制求最大公约数最多循环15次。因此只需要for循环多于相应的次数即可出结果,for(n=0;n<15;n=n+1)。
后面我们小组又做了提高任务,将2个四位二进制变成了2个八位二进制,循环次数变为了128,可以用led很容易来表示对应的结果。
五、 心得体会
在进行本次实验时,我首先从最大公约数的原理入手,只做了基础部分和提高部分,这里我程序原理设计用的是更相减损法。
做基础任务,编写源代码时,我首先看到的书上的程序,书上用的是一个while语句来进行循环,但是仿真时会有错误,因为while的循环次数是无限的,仿真时无法构架电路。但是我没有按照书上的程序进行顶层模块的调动,来实现求最大公约数。而是用了一个for循环,确定2个四位二进制求最大公约数最多循环15次。因此只需要for循环多于相应的次数即可出结果,for(n=0;n<15;n=n+1)。
后面我又做了提高任务,将2个四位二进制变成了2个八位二进制,循环次数变为了128,可以用led很容易来表示对应的结果。但是题中要求用数码管显示结果,因此首先需要将求出的结果转化为十进制,然后用数码管循环显示。由于我在做组合逻辑电路时,没有做二进制转十进制的实验,因此,需要重新编程,导致我另外设计了二进制转十进制的程序,验证正确后,才加入了原程序中。这里我并没有用层次化设计,而是将其放在了一个程序中。转化时8次移位全部完成,将对应的值分别赋给个,十,百位,然后led_pin[15:10]=6’b000000; led_pin[9:0]=shift_reg[17:8];将重新赋值后的led_pin用数码管显示。