ZYBO Z7 实现计算最大公约数

news/2025/1/11 15:10:34/

目录

1. 前言

2. 运行环境

3.实现原理

4. 实现过程

5. 代码

顶层代码

输入模块

状态机模块

计算模块

显示模块

约束文件

6. 功能仿真


1. 前言

        近期在学习EDA课程,课上学习了一部分关于使用Verilog语言实现求两个数的最大公约数的算法,课后在完成作业的时候看到了一篇关于在ZYBO Z7实现四位全加器的博客,于是参考该代码的输入及显示方式,实现了使用ZYBO Z7来计算最大公约数的功能,但是ZYBOZ7开发板的拨码只有4个,所以只能计算2个4位数的最大公约数。

部分参考程序:

四位全加器的FPGA实现_hfutstudenthuang的博客-CSDN博客_fpga四位加法器

2. 运行环境

1. 软件:vivado 2018.3

2. FPGA开发板:ZYBO Z7

3.实现原理

最大公约数的算法流程图如下:

在以上过程中,存在使用除法求余数的步骤。用硬件实现除法开销较大,所以使用减法来实现,除法取余数本质上是不断做减法直到被除数小于除数。

4. 实现过程

RTL图如下:

 其中共包括4个模块,即

        输入模块:通过FPGA上的拨码即按钮进行两个数据的输入,以及使用开关控制结果出输出及复位。

        状态机模块:规模较小的数字系统/子系统的控制逻辑一般采用状态机来实现。根据需求,对应的计算过程可以分为等待输入、计算、等待输出等三步。

        计算模块:计算过程。

        显示模块:通过LED灯来显示输入数据、运算结果。

5. 代码

顶层代码

`timescale 1ns/100ps//时间精度
//定义值
`define A_SEL_X   2'bxx
`define A_SEL_IN  2'b00
`define A_SEL_B   2'b01
`define A_SEL_SUB 2'b10
`define B_SEL_X   1'bx
`define B_SEL_IN  1'b0
`define B_SEL_A   1'b1
//顶层模块
module gcd_rtl_top #(parameter W=4)(input		clk,                   //时钟信号input		reset,                 //复位信号input wire bottom1,              //开关(控制数据1输入)input wire bottom2,              //开关2(控制数据2输入)input wire bottom3,              //开关3(控制输出结果)input wire [W-1:0] data,         //当前的数据output wire [3:0] display_result,//输出结果output    result_rdy              //运算状态
);//定义中间数据类型wire [W-1:0] result_data;      //运算结果wire   A_en;wire   B_en;wire [1:0] A_sel;wire   B_sel;wire   B_zero;wire   A_lt_B;wire [W-1:0] operand_A;        //数据1wire [W-1:0] operand_B;        //数据2//调用子模块
//输入模块
data_in data_in(.clk(clk),.reset(reset),.bottom1(bottom1),.bottom2(bottom2),.data(data),.operand_A(operand_A),.operand_B(operand_B));//状态机模块
gcdGCDUnitCtrl gcdUC(.clk(clk), .reset(reset), .A_en(A_en), .B_en(B_en),.A_sel(A_sel), .B_sel(B_sel), .result_rdy(result_rdy), .B_zero(B_zero), .A_lt_B(A_lt_B));//计算模块
gcdGCDUnitDpath gcdUD(.clk(clk),.operand_A(operand_A), .operand_B(operand_B), .result_data(result_data), .A_en(A_en),.B_en(B_en),.A_sel(A_sel),.B_sel(B_sel),.B_zero(B_zero), .A_lt_B(A_lt_B));//显示模块
display display(.clk(clk),.reset(reset),.bottom1(bottom1),.bottom2(bottom2),.bottom3(bottom3),.result_data(result_data),.display_result(display_result),.result_rdy(result_rdy),.data(data));
endmodule

输入模块

`timescale 1ns / 1ps
//定义输入/输出
module data_in(input clk,input reset,input bottom1, input bottom2,input [3:0] data, output reg[3:0] operand_A=1,output reg[3:0] operand_B=1);always @(posedge clk or posedge reset)beginif(reset)                              //按下复位键时数据1,2都为0.beginoperand_A<= 0;operand_B<= 0;endelsebeginif(bottom1)                    //bottom1按下时,数据1接收当前输入数据beginoperand_A <= data;endelse if(bottom2)               //bottom2按下时,数据2接收当前输入数据beginoperand_B <= data;endendend
endmodule

 状态机模块

`timescale 1ns/100ps
`define A_SEL_X   2'bxx
`define A_SEL_IN  2'b00
`define A_SEL_B   2'b01
`define A_SEL_SUB 2'b10
`define B_SEL_X   1'bx
`define B_SEL_IN  1'b0
`define B_SEL_A   1'b1
module gcdGCDUnitCtrl 
#(parameter W = 4)//数据位数(input		clk,input		reset,input		B_zero,            input		A_lt_B,             output reg	A_en,        output reg	B_en,             output reg [1:0]	A_sel,         output reg	B_sel,         output reg	result_rdy
);localparam WAIT = 2'd0;localparam CALC = 2'd1;localparam DONE = 2'd2;            //三种状态reg  [1:0] state_next;             //下次状态wire [1:0] state;                  //当前状态//复位信号vcRDFF_pf state_pf( .clk     (clk),.reset_p (reset),.d_p     (state_next),.q_np    (state)  );always @(*)begin //控制信号                                                                        A_sel    = `A_SEL_X;             //定义初始值A_en     = 1'b0;                 B_sel    = `B_SEL_X;B_en     = 1'b0;result_rdy   = 1'b0;             //表示计算未结束case ( state )WAIT: begin                    //位于WAIT状态,读取数据A_sel = `A_SEL_IN;A_en  = 1'b1;B_sel = `B_SEL_IN;B_en = 1'b1;endCALC:                      //位于计算状态begin                    if ( A_lt_B )          //当A_lt_B=1时beginA_sel = `A_SEL_B;A_en     = 1'b1;B_sel = `B_SEL_A;B_en      = 1'b1;endelse if ( !B_zero )      //当B_zero不为0时beginA_sel = `A_SEL_SUB;A_en      = 1'b1;endendDONE: result_rdy = 1'b1;      //位于计算结束状态endcaseendalways @(*)                         //运算过程beginstate_next = state;              // 默认保持当前状态case ( state )WAIT :state_next = CALC;             CALC :if ( B_zero) beginstate_next = DONE;endDONE :state_next = WAIT;endcase
end
endmodule
`timescale 1ns / 1ps
module vcRDFF_pf
(	input clk,input reset_p,input[1:0] d_p,output reg[1:0] q_np  
);localparam WAIT = 2'd0;localparam CALC = 2'd1;localparam DONE = 2'd2;always @( posedge clk or posedge reset_p )
beginif( reset_p )                   //当复位为1时,状态为WAITq_np <= WAIT;elseq_np <= d_p;                //当复位为0时,状态为下一状态
endendmodule

计算模块

module gcdGCDUnitDpath #(parameter W = 4)
( input      clk,input  [W-1:0] operand_A,   input  [W-1:0] operand_B,   output [W-1:0] result_data,  input          A_en,              input          B_en,             input    [1:0] A_sel,         input          B_sel,         output         B_zero,            output         A_lt_B             
);wire [W-1:0] B;wire [W-1:0] sub_out;wire [W-1:0] A_out;// 3-1多路复用器vcMux3#(W) A_mux( .in0 (operand_A),.in1 (B),.in2 (sub_out),.sel (A_sel),.out (A_out)   );wire [W-1:0] A;// register with enablevcEDFF_pf#(W) A_pf( .clk  (clk),.en_p (A_en),.d_p  (A_out),.q_np (A)      );wire [W-1:0] B_out;// 2-1多路复用器vcMux2#(W) B_mux( .in0 (operand_B),.in1 (A),.sel (B_sel),.out (B_out)    );// register with enablevcEDFF_pf#(W) B_pf( .clk  (clk),.en_p (B_en),.d_p  (B_out),.q_np (B)      );assign B_zero  = (B==0);    assign A_lt_B  = (A < B);  assign sub_out = A - B;assign result_data = A;
endmodule
`timescale 1ns/100ps
`define A_SEL_X   2'bxx
`define A_SEL_IN  2'b00
`define A_SEL_B   2'b01
`define A_SEL_SUB 2'b10
`define B_SEL_X   1'bx
`define B_SEL_IN  1'b0
`define B_SEL_A   1'b1
module vcMux3 #(parameter W = 4)
(input[W-1:0] in0,input[W-1:0] in1,input[W-1:0] in2,input[1:0] sel,output reg[W-1:0] out
);	always @(*)begincase(sel)`A_SEL_IN : out <= in0;`A_SEL_B : out <= in1;`A_SEL_SUB : out <= in2;endcaseend
endmodule
`timescale 1ns/100ps
`define A_SEL_X   2'bxx
`define A_SEL_IN  2'b00
`define A_SEL_B   2'b01
`define A_SEL_SUB 2'b10
`define B_SEL_X   1'bx
`define B_SEL_IN  1'b0
`define B_SEL_A   1'b1module vcMux2 #(parameter W = 4)
(input [W-1:0] in0,input [W-1:0] in1,input sel,output reg[W-1:0] out
);always @(sel)begincase(sel)`B_SEL_IN : out <= in0;`B_SEL_A : out <= in1;endcaseend
endmodule
`timescale 1ns/100ps
`define A_SEL_X   2'bxx
`define A_SEL_IN  2'b00
`define A_SEL_B   2'b01
`define A_SEL_SUB 2'b10
`define B_SEL_X   1'bx
`define B_SEL_IN  1'b0
`define B_SEL_A   1'b1
module vcEDFF_pf #(parameter W = 4)
(input clk,input en_p,input[W-1:0] d_p,output reg[W-1:0] q_np
);always @(posedge clk)beginif(en_p) beginq_np <= d_p;endend
endmodule

显示模块

`timescale 1ns / 1ps
module display(input clk,input reset,input bottom1,input bottom2,input bottom3,input carry_out,input [3:0] result_data,output reg [3:0] display_result,input result_rdy,input [3:0] data);always @(posedge clk or posedge reset)beginif(reset)                                     //按下复位键,输出清0begindisplay_result <= 0;endelsebeginif(bottom3&result_rdy)                  //bottom3按下时,显示求和结果以及进位输出begindisplay_result <= result_data;endelse if(bottom1)                        //bottom1按下时,显示输入数据begindisplay_result <=data;endelse if(bottom2)                        //bottom2按下时,显示输入数据begindisplay_result <= data;endendend
endmodule

约束文件

##Clock signal
set_property -dict { PACKAGE_PIN K17   IOSTANDARD LVCMOS33 } [get_ports { clk }]; 
create_clock -add -name sys_clk_pin -period 8.00 -waveform {0 4} [get_ports { clk }];##Switches
set_property -dict { PACKAGE_PIN G15   IOSTANDARD LVCMOS33 } [get_ports { data[0] }]; 
set_property -dict { PACKAGE_PIN P15   IOSTANDARD LVCMOS33 } [get_ports { data[1] }]; 
set_property -dict { PACKAGE_PIN W13   IOSTANDARD LVCMOS33 } [get_ports { data[2] }]; 
set_property -dict { PACKAGE_PIN T16   IOSTANDARD LVCMOS33 } [get_ports { data[3] }]; ##Buttons
set_property -dict { PACKAGE_PIN K18   IOSTANDARD LVCMOS33 } [get_ports { reset }]; 
set_property -dict { PACKAGE_PIN P16   IOSTANDARD LVCMOS33 } [get_ports { bottom1 }]; 
set_property -dict { PACKAGE_PIN K19   IOSTANDARD LVCMOS33 } [get_ports { bottom2 }]; 
set_property -dict { PACKAGE_PIN Y16   IOSTANDARD LVCMOS33 } [get_ports { bottom3 }]; ##LEDs
set_property -dict { PACKAGE_PIN M14   IOSTANDARD LVCMOS33 } [get_ports { display_result[0] }]; 
set_property -dict { PACKAGE_PIN M15   IOSTANDARD LVCMOS33 } [get_ports { display_result[1] }]; 
set_property -dict { PACKAGE_PIN G14   IOSTANDARD LVCMOS33 } [get_ports { display_result[2] }]; 
set_property -dict { PACKAGE_PIN D18   IOSTANDARD LVCMOS33 } [get_ports { display_result[3] }]; ##RGB LED 5 
set_property -dict { PACKAGE_PIN Y11   IOSTANDARD LVCMOS33 } [get_ports { result_rdy }]; 

6. 功能仿真

编写仿真文件:

`timescale 1ns / 1ps
module gcd_rtl_test;
parameter W = 4;
reg clk = 0;
reg reset = 1;
reg bottom1;
reg bottom2;
reg bottom3;
reg [W-1:0] data;
wire [W-1:0] display_result;
gcd_rtl_top #(4) gcd_rtl(.clk(clk),.reset(reset),.bottom1(bottom1),.bottom2(bottom2),.bottom3(bottom3),.display_result(display_result),.data(data)
);
always #10 clk =~clk;initial beginclk <= 0;reset <= 1;bottom1 <= 0;bottom2 <= 0;bottom3 <= 0;#20 reset = 0;   #20 bottom1<=1;data <= 4'd6; #20 bottom1<=0;bottom2<=1;data<= 4'd9; #20 bottom1<=0;bottom2<=0;#20bottom3 <= 1;endendmodule

点击run simulation仿真结果如下:

当bottom1按下时,显示结果为6,即第一个输入。

当bottom2按下时,显示结果为9,即第二个输入。

当bottom3按下时,显示为3,运算正确。

7. 结果

点击generate bitstream生成比特流文件;

将zybo z7连接电脑,之后点击open hardware manager,点击open target - auto connect。最后将比特流文件烧录进ZYBO Z7。绿灯亮起,即可以正常使用功能。

拨动开关输入数据4'b 0110(6),按下右下角从右向左第二个开关(即bottom1),显示0110.

拨动开关输入数据4'b 1001(9),按下右下角从右向左第三个开关(即bottom2),显示1001.

 按下右下角从右向左第四个开关(即bottom3),显示结果0011(3)。 

按下右下角从右向左第一个开关(即reset),显示归0.


http://www.ppmy.cn/news/160984.html

相关文章

神舟战神z7使用U盘重装系统操作教程分享

神舟战神z7使用U盘重装系统操作教程分享。有用户使用神舟战神z7笔记本电脑的时候安装了一个程序导致了电脑中毒&#xff0c;系统出现了损坏&#xff0c;无法正常的使用。今天教你如何通过U盘重装系统的方法来进行系统的重置&#xff0c;恢复正常的电脑使用。 准备工作&#xff…

FME教程:批量提取面要素图形的拐点坐标到Excel,其他类型图形的坐标提取、输出可参考本文方法

目录 一、提取成果 二、实现过程 1.读取数据 2.分离内外边界 3.提取坐标 4.获取边界序号 5.坐标处理 6.数据输出 三、总结 今天给大家介绍使用FME提取几何图形拐点坐标&#xff0c;并输出到Excel中的案例。这里以shapefile格式&#xff0c;且内部存在环洞的面要素为例…

跨境电商平台支持后台采集商城PC+WAP+小程序+APP,Java

跨境电商系统概述 跨境电商系统是一种在全球范围内开展电子商务的技术平台。它能够帮助企业建立贸易关系、实现商品销售、支付和物流配送等功能&#xff0c;提高企业的市场竞争力和盈利能力。该系统支持自营和招商入驻的电商模式&#xff0c;多终端交互&#xff0c;有PC、APP、…

Learn From Microsoft Build Ⅲ:低代码

点击蓝字 关注我们 编辑&#xff1a;Alan Wang 排版&#xff1a;Rani Sun 微软 Reactor 为帮助广开发者&#xff0c;技术爱好者&#xff0c;更好的学习 .NET Core, C#, Python&#xff0c;数据科学&#xff0c;机器学习&#xff0c;AI&#xff0c;区块链, IoT 等技术&#xff0…

第二十二章 开发Productions - ObjectScript Productions - 生成警报

文章目录 第二十二章 开发Productions - ObjectScript Productions - 生成警报生成警报添加Trace Elements在 ObjectScript 中编写跟踪消息用BPL或DTL编写跟踪消息 第二十二章 开发Productions - ObjectScript Productions - 生成警报 生成警报 如果发生警报事件&#xff0c;…

音乐相册android studio,音乐相册

音乐相册是一款让用户可以快速的制作出对应相册带来更美好记录的手机app。每一位人群现在都是会经常的拍照&#xff0c;毕竟我们拍照可以进行实时性的留恋&#xff0c;和朋友一起出去玩&#xff0c;同学聚会&#xff0c;到某些地方旅游&#xff0c;和喜欢的人在一起的时候等&am…

相册视频制作APP有什么推荐?看这里!轻松把照片做成视频

手机上做相册视频操作不够方便&#xff0c;出来的效果也不如电脑上的。想快速做一个比较酷炫吸睛的相册视频&#xff0c;还是在电脑上制作更好&#xff0c;用一个简单好上手还特效多的相册视频制作软件就行。 下面教大家用数码大师快速把照片做成相册视频&#xff0c;具体步骤…

Sony vegas 制作电子相册

生活中有太多值得记录的事情&#xff0c;执子之手与子同老的浪漫爱情&#xff0c;宝宝牙牙学语的成长点滴&#xff0c;旅途中的前途风景&#xff0c;太多的美好与感动&#xff0c;让我们总想通过一些途径去与身边的人分享。对于目前来说&#xff0c;电子相册无疑是最绝妙的分享…