fpga实操训练(仿真和状态机)

news2024/11/19 9:29:44

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        在进行fpga上板子实验之前,相信很多同学都是通过仿真的方式来实现verilog学习的。仿真比较容易,也不需要依赖物理硬件,所以一般是大家比较认可的学习方法。等接触了fpga开发板之后,很多同学认为,这样就不需要进行仿真测试了。其实这种想法就大错特错了,通过了仿真测试的电路不一定可以在fpga上面运行起来,但是没有通过仿真测试的电路是根本没有可能正常运行的。

        除此之外,相信经过这么几次上机测试,大家还发现了fpga实际运行的几个问题:1)编译、综合的速度其实非常慢,至少比自己之前编译软件的时间多多了;2)调试的手段不多。fpga调试一般会有这么几种方法,a、用led、uart输出有用的信息;b、用示波器、逻辑分析仪测量信号;c、用signal tap或者chipscope这样内置的逻辑分析仪+jtag进行调试。但是上面说到的三种调试方法,每一次都需要重新编译、综合版本,这又相当于回到了问题1,那就是重新综合花费的时间比较多、速度比较慢。

        所以为了解决fpga的问题,还是建议大家,在真正把verilog运行到fpga之前,先完成仿真的工作。仿真的速度非常快,而且很容易修改和验证。对于开发者来说,至少先保证仿真时没有逻辑的错误之后,再到fpga上面进行测试验证,这样要比直接在fpga上面开发效率要高很多。

        当然,今天除了仿真之外,另外一个要说的就是状态机。状态机在fpga上面用的非常多。从底层的硬件逻辑,到上层的模块逻辑、算法逻辑,用的都非常多。建议这部分,大家可以好好掌握一下。

        为了说明状态机怎么使用。我们可以通过一个示例来进行说明。之前,谈到过数据累加的程序。今天,可以把这个程序改一下。比如先从1累加到9,再从9递减到1。从1加到9,在从9减到1,这里面过程都是独立的。因此,可以把这两个过程看成是两个独立的状态,1加到9是状态1,9减到1是状态2,这么来分析的话,事情就变得简单了。


module state_machine(clk, rst, data);

localparam SECOND_INTERVAL=32'd50;

input clk;
input rst;
output [7:0] data;

wire clk;
wire rst;
reg[7:0] data;


reg[31:0] count;

reg[1:0] state;
reg[1:0] next_state;

// register count
always@(posedge clk or negedge rst)
	if(!rst)
		count <= 32'd0;
	else if(count == SECOND_INTERVAL)
		count <= 32'd0;
	else
		count <= count + 1;

// output data
always @(posedge clk or negedge rst)
	if(!rst)
		data <= 8'd0;
	else if(count == SECOND_INTERVAL && state == 2'b00)
		data <= data + 1;
	else if(count == SECOND_INTERVAL && state == 2'b01)
		data <= data - 1;

// state machine
always@(posedge clk or negedge rst)
	if(!rst)
		state <= 2'b00;
	else
		state <= next_state;
		
// next state
always@(*)
	if(!rst)
		next_state <= 2'b00;
	else
		case (state)
			2'b00:
				if(data == (9-1) && count == SECOND_INTERVAL)
					next_state <= 2'b01;
				else
					next_state <= 2'b00;
			
			2'b01:
				if(data == (1+1) && count == SECOND_INTERVAL)
					next_state <= 2'b00;
				else
					next_state <= 2'b01;
				
			default:
				next_state <= 2'b00;
		endcase

endmodule


        上述代码中的2'b00就是状态1,2'b01就是状态2,注意下两个状态的切换条件。只有当data等于8,并且count等于SECOND_INTERVAL的时候,next_state才会切换为2'b01。但是因为当前状态还是2'b00,所以data还会自增1,达到9。但是下一次的时候,data就开始自减了。有了state从2'b00切换为2'b01,那么它从2'b01切换为2'b00也是一样的道理。

`timescale 1ns/1ps
module show_seg_tb();
 
reg rst;
reg clk;
wire[7:0] data;
 
state_machine state_machine0(
	.rst(rst),
    .clk(clk),
    .data(data));
 
initial
    begin
        rst = 1;
        clk = 0;
        #12 rst = 0;
        #21 rst = 1;
        #100000 $finish;
    end
 
 
initial
begin
    while(1)
    clk = #5 !clk;
end
 
initial
begin
    $dumpfile("hello.vcd");
    $dumpvars(0, state_machine0);
end
 
endmodule

        为了验证我们编写的代码是否正确,有必要编写一个testbench代码。这里使用的工具还是iverilog+gtkwave来完成的。

         通过了testbench之后,这样才能保证代码的基本功能才是正确的。完成了仿真和test bench之后,下面就可以准备把这段代码port到fpga上面了,当前要做一点小的修改,主要是增加数码管显示的部分。

module seg_test(clk, rst, sel, seg_data);

localparam SECOND_INTERVAL=32'd4999_9999;

input clk;
input rst;
output [5:0] sel;
output [7:0] seg_data;

wire clk;
wire rst;
reg[7:0] data;
reg [5:0] sel;
reg [7:0] seg_data;


reg[31:0] count;

reg[1:0] state;
reg[1:0] next_state;

// output sel and out
always@(posedge clk or negedge rst)
	if(!rst)
		sel <= 6'b011111;
	else
		sel <= sel;


always@(posedge clk or negedge rst)
		if(!rst)
			seg_data <= 8'b1100_0000;
		else
			case (data)
				4'd0: 
					seg_data <= 8'b1100_0000;				
				4'd1: 
					seg_data <= 8'b1111_1001;
				4'd2: 
					seg_data <= 8'b1010_0100;
				4'd3: 
					seg_data <= 8'b1011_0000;
				4'd4: 
					seg_data <= 8'b1001_1001;
				4'd5: 
					seg_data <= 8'b1001_0010;
				4'd6:
					seg_data <= 8'b1000_0010;
				4'd7:
					seg_data <= 8'b1111_1000;
				4'd8:	
					seg_data <= 8'b1000_0000;
				4'd9:
					seg_data <= 8'b1001_0000;
					
				default: 
					seg_data <= 8'b1100_0000;
			endcase
		
// register count
always@(posedge clk or negedge rst)
	if(!rst)
		count <= 32'd0;
	else if(count == SECOND_INTERVAL)
		count <= 32'd0;
	else
		count <= count + 1;

// output data
always @(posedge clk or negedge rst)
	if(!rst)
		data <= 8'd0;
	else if(count == SECOND_INTERVAL && state == 2'b00)
		data <= data + 1;
	else if(count == SECOND_INTERVAL && state == 2'b01)
		data <= data - 1;

// state machine
always@(posedge clk or negedge rst)
	if(!rst)
		state <= 2'b00;
	else
		state <= next_state;
		
// next state
always@(*)
	if(!rst)
		next_state <= 2'b00;
	else
		case (state)
			2'b00:
				if(data == (9-1) && count == SECOND_INTERVAL)
					next_state <= 2'b01;
				else
					next_state <= 2'b00;
			
			2'b01:
				if(data == (1+1) && count == SECOND_INTERVAL)
					next_state <= 2'b00;
				else
					next_state <= 2'b01;
				
			default:
				next_state <= 2'b00;
		endcase

endmodule

        编译、综合没有问题后,就可以开始进行pin脚的bind,这部分和之前没有什么区别,

         烧入后,如果没有问题的话,就可以看到对应的测试内容了,即先增加到9,再递减到1,循环反复。

        所以说,通过今天的状态机实验告诉我们,虽然实际调试板子非常方便,但是效率不太高。如果想更有效率地实现fpga的开发工作,最好还是先编写仿真代码,然后再port到fpga开发板子上面,这样常常会有事半功倍的效果。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/112543.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

offsetTop、clientTop、scrollTop等属性详解【概念+详细例子分析】

文章目录一、 offsetscrollclient详细讲解1-1 offset系列1-2 client系列1-3 scroll系列二、 一张图片即可理解一、 offsetscrollclient详细讲解 1-1 offset系列 MDN中offset… offsetWidth/offsetHeight :对象的可见宽度offsetLeft/offsetTop&#xff1a; 当前元素距浏览器边界…

AcWing第 82 场周赛

第k个数 给定一个长度为 nn 的整数数列 a1,a2,…,ana1,a2,…,an&#xff0c;以及一个整数 kk。 请你计算并输出该数列从大到小排序后的第 kk 个数。 输入格式 第一行包含两个整数 n,kn,k。 第二行包含 nn 个整数 a1,a2,…,ana1,a2,…,an。 输出格式 一个整数&#xff0c…

map与set详解

&#x1f9f8;&#x1f9f8;&#x1f9f8;各位大佬大家好&#xff0c;我是猪皮兄弟&#x1f9f8;&#x1f9f8;&#x1f9f8; 文章目录一、两个概念二、set①set的两种遍历方式②set的erase③set的count三、map①SGI-STL中关于键值对的定义②map的insert③访问键值对④map的op…

docker redis容器化(极简教程)

1.通过redis-cli连接你原来的redis&#xff0c;进入后输入info&#xff0c;查看到具体版本号 2.下载redis官方镜像,docker pull redis:你的版本号 3.创建一个新文件夹redis&#xff0c;mkdir -r /hadoop/redis 4.复制你原来的redis.conf&#xff0c;到redis文件夹中,cp /usr/l…

c语言 指针进阶5 6 自定义冒泡函数 qsort

指向函数指针数组的指针 回调函数 如何使用 一个函数可以实现加减乘除 calc&#xff08;&#xff09; 不同点通过函数参数传进去 代码解释如下 int Add(int x, int y) {return x y; } int Sub(int x, int y) {return x - y; } int Mul(int x, int y) {return x * y; } in…

JDBC -- API

目录 DriverManager 驱动管理类 作用 注册驱动 获取数据库连接 Connection 数据库连接对象 作用 获取执行SQL的对象 管理事务 Statement 作用 执行SQL语句 ResultSet 结果集对象 作用 封装了DQL查询语句的结果 获取查询结果 PreparedStatement 作用 预编译SQ…

C#大型医院HIS系统源码 医院信息管理系统源码 C/S架构 VS2013+sql2012

了解更多源码内容&#xff0c;可私信我。 开发环境&#xff1a;VS2013sql2012 C/S架构 一、门诊系统&#xff1a; 1、挂号与预约系统:实现了医院门诊部挂号处所需的各种功能&#xff0c;包括门诊安排的管理&#xff0c;号表的生成及维护&#xff0c;门诊预约管理和挂号处理&…

6. SSM整合

1. SSM整合配置 SM整合流程 创建工程SSM整合 Spring SpringConfig MyBatis MybatisConfigJdbcConfigjdbc.properties SpringMVC ServletContainerInitConfigSpringMvcConfig 1.1 创建工程&#xff0c;添加依赖和插件 <dependencies><dependency><groupId&g…

【LeetCode】解数独 [H](深度优先遍历)

37. 解数独 - 力扣&#xff08;LeetCode&#xff09; 一、题目 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只…

设计模式-责任链模式

一、知其然 责任链字面含义第一联想到的就是他是一个链式的行为&#xff0c;就像一个链条一样把所产生的动力传输到到齿轮上一样&#xff1b;还有类似生活中的一个游戏“击鼓传花”&#xff0c;这样说好像也是泛泛而谈&#xff0c;来看看度娘的官方概念&#xff08;摘自百度百科…

[每周一更]-(第26期):反爬虫机制

随着网站的越来越普及&#xff0c;我们开发出来的知识类网站更不希望被竞争对手爬虫&#xff0c;虽然现在网络中充斥着各种各样的蜘蛛&#xff0c;有合法的浏览器爬虫&#xff0c;以及不合法 的人为爬虫&#xff0c;所以攻防战一直都存在&#xff0c;我们只能更好的设定规则&am…

中文文本分类

手把手带你做一个文本分类实战项目(模型代码解读) https://www.bilibili.com/video/BV15Z4y1S7aR/?spm_id_from333.788.recommend_more_video.-1&vd_sourcec47fbb8166930edc486d8fdc405bf569 中文汉字对应的数字索引 之后对应的数字索引 之后找到tokn embedding的东西 1…

34. 池化层 / 汇聚层

1. 池化层 如果我们拍摄黑白之间轮廓清晰的图像X&#xff0c;并将整个图像向右移动一个像素&#xff0c;即Z[i, j] X[i, j 1]&#xff0c;则新图像Z的输出可能大不相同。而在现实中&#xff0c;随着拍摄角度的移动&#xff0c;任何物体几乎不可能发生在同一像素上。即使用三脚…

15【SpringMVC的注解开发】

文章目录二、SpringMVC注解支持2.1 回顾Servlet容器启动源码流程2.2 分析SpringMVC启动源码分析2.2.1 SpringServletContainerInitializer源码分析2.2.2 WebApplicationInitializer源码分析1&#xff09;AbstractContextLoaderInitializer2&#xff09;AbstractDispatcherServl…

短视频播放量超10w后,流量变少的问题解决方案

短视频播放量超10w后&#xff0c;流量变少的问题解决方案 上一篇我们聊了视频播放超10w后&#xff0c;会遇到流量变少的问题并分析了可能的原因&#xff0c;既然知道了原因&#xff0c;那么我们就可以针对性的去解决了。 今天给大家聊一聊在我赢助手跟超200名短视频创作者沟通…

Allegro如何设置差分动态等长规则操作指导

Allegro如何设置差分动态等长规则操作指导 Allegro上可以对差分设置动态等长规则,让差分对在任意一段距离上都是满足等长误差的,尤其是在差分对走线较长的情况下 以下面这两对线为例 具体操作如下 打开constraint Manage选择Physical规则

Linux 管理联网 设置主机名( nmtui图形化 和 hostnamectl命令 )

设置主机名 # 常用的有两种方式&#xff0c;一种是 nmtui 图形化界面的方式来设置&#xff0c; 一种是 hostnamectl 命令的方式来设置。 nmtui 直接在命令行 输入 nmtui 便进入 图形化界面 >>> 最后一选项&#xff08; 红底&#xff09; 便是 设置主机名~&#x…

微导纳米科创板上市:市值125亿 无锡首富王燕清再敲钟

雷递网 雷建平 12月23日江苏微导纳米科技股份有限公司&#xff08;简称&#xff1a;“微导纳米”&#xff0c;股票代码为&#xff1a;“688147”&#xff09;今日在科创板上市。微导纳米此次发行4544.55万股&#xff0c;发行价为24.21元&#xff0c;募资总额为11亿元。微导纳米…

react笔记_11 redux

目录redux定义使用时机redux基本概念StoreStateActionreducerredux工作原理语法[1] 创建StorecreateStorecombineReducers[2]创建并分发actiondispatchapplyMiddleware语法举例说明- 做一个加法运算执行原理redux-thunk中间件使用[3]创建reducer语法渲染过程[4]getState[5]subs…

基于meanshift算法的目标聚类和目标跟踪matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 meanshift算法其实通过名字就可以看到该算法的核心&#xff0c;mean&#xff08;均值&#xff09;&#xff0c;shift&#xff08;偏移&#xff09;&#xff0c;简单的说&#xff0c;也就是有一个…