【PFPGA学习】状态机思想编程HDLbitsFPGA练习

news2025/4/15 3:57:52

目录

一、用状态机实现LED流水灯

1.1状态机思想

1.2状态机思想LED流水灯

1.3 modesim仿真

1.4 FPGA烧录实现

二、CPLD和FPGA芯片

1. 核心结构与技术原理

2. 性能与容量

3. 适用场景

4. 选型建议

三、HDLbitsFPGA练习记录(combinational logic)

练习一:7420chip

练习二:电路描述

 练习三、多路选择器1-9

练习四:Full adder

 练习五、Bcdadd4

四、总结

前言:

  1. 掌握状态机思想在FPGA开发中的应用。

  2. 学习Modelsim仿真与DE2-115开发板验证流程。

  3. 理解CPLD与FPGA技术差异及适用场景。

  4. 通过HDLbits刷题巩固组合逻辑设计能力。

一、用状态机实现LED流水灯

1.1状态机思想

状态机(Finite State Machine, FSM) 是一种描述系统状态转移的数学模型,广泛应用于时序逻辑设计。在FPGA中,状态机通过明确的状态划分和转移条件,简化复杂控制流程的设计。

①现态:是指当前所处的状态。

②条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。

③动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。

④次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。

核心要素

  • 现态(Current State):系统当前所处的状态。

  • 事件(Event):触发状态迁移的条件(如用户输入、传感器信号等)。

  • 动作(Action):状态迁移时执行的操作(如开启设备、发送数据等)。

  • 次态(Next State):事件触发后系统将进入的新状态。

分类与模型

  • Moore型:输出仅由当前状态决定(如交通信号灯的红绿灯切换)。

  • Mealy型:输出由当前状态和输入共同决定(如网络协议中的应答机制)。

  • 确定型(DFA):每个状态对同一事件有唯一迁移路径。

  • 非确定型(NFA):同一事件可能触发多个迁移路径,需额外逻辑处理。

1.2状态机思想LED流水灯

1.代码编写(verilog):

状态机通过定义不同的状态和状态之间的转换逻辑,能够精确地控制LED灯的点亮顺序。在代码中,S0S7这8个状态分别对应着8个LED灯依次点亮的状态。通过状态的转换,实现了LED流水灯的效果。

module led_fsm(
    input clk,          // 50MHz时钟
    input rst_n,        // 复位信号(低有效)
    output reg [7:0] led
);
    // 状态定义(8个状态)
    localparam [2:0] S0=0, S1=1, S2=2, S3=3, S4=4, S5=5, S6=6, S7=7;
    reg [2:0] state;
    reg [24:0] cnt;
    wire en = (cnt == 25'd24_999_999); // 分频使能

    // 分频计数器
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) cnt <= 0;
        else if (en) cnt <= 0;
        else cnt <= cnt + 1;
    end

    // 状态机主逻辑
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            state <= S0;
            led <= 8'b00000001; // 初始状态S0点亮LED0
        end
        else if (en) begin
            case(state)
              S0: begin led <= 8'b00000010; state <= S1; end  //S0→S1(第2个LED亮)
                S1: begin led <= 8'b00000100; state <= S2; end  //S1→S2(第3个LED亮)
              S2: begin led <= 8'b00001000; state <= S3; end  //S2→S3(第4个LED亮)
             S3: begin led <= 8'b00010000; state <= S4; end  //S3→S4(第5个LED亮)
                S4: begin led <= 8'b00100000; state <= S5; end  //S4→S5(第6个LED亮)
                S5: begin led <= 8'b01000000; state <= S6; end  //S5→S6(第7个LED亮)
             S6: begin led <= 8'b10000000; state <= S7; end  //S6→S7(第8个LED亮)
                S7: begin led <= 8'b00000001; state <= S0; end  //S7→S0(第1个LED亮,循环)
            default: state <= S0;                          // 默认回到初始状态
            endcase
        end
    end
endmodule

1.3 modesim仿真

创建工程文件后,跟着步骤来进行仿真操作(可参考参考文件三仿真步骤比较详细,由于之前的博客写过步骤,我就只保存截图了关键部分)

设置成为顶层文件后编译代码

点击Processing-->Start-->Start test bench template writer,这时我们的文件夹之下已经有了一个example.vt文件

(默认是保存在当前目录simulationmodelsim文件夹下的.vt格式文件。)对刚才生成的文件进行修改(可以直接复制下面代码,注意修改文件名称),然后在编译一次

`timescale 1ns/1ns
 
module led_fsm;
   reg        clk;
	reg        rst_n;
	reg        data;
	
	wire       pos_edge;
   wire       neg_edge;
   wire       data_edge;
	wire [1:0] D;
 
 
  example   u1(
      .clk(clk),
      .rst_n(rst_n),
      .data(data),
    
      .pos_edge(pos_edge),
      .neg_edge(neg_edge),
      .data_edge(data_edge),
		.D(D)
 );
 
 //产生时钟激励
 initial  clk = 1; 
 always #10  clk = ~clk;
 
 
 //输入激励
 initial  begin 
      rst_n=0;
		data=0;
      #100;
      rst_n = 1;
		#50
      data=1;
      #201;
      data=0;
      #201;
      data=1; 
      #101;
      data=0;	
      #200;
      $stop;
 
 end
 
 endmodule 

 现在设置仿真,点击Tools-->Options-->EDA ToolsOptions选项,点击浏览Modelsim安装目录下的Win64或者Win32

4、然后对仿真文件设置点击Assignments-->Settings,再点击下面的Simulation按照如图设置

5、选择上面的Compile test bench点击后面Test Bench进入选择,点击New新建

按照顺序先编辑名字,然后浏览刚才的.vt文件,最后点击Add添加达到如下图效果,再点击OK,这里如果浏览的是.vo文件则后面仿真需要自己设置时间及电平,然后一直点击OK回到代码编辑界面

 来到主页点击:自动跳转至Modelsim,选择下面的Wave即可看到波形。

 

1.4 FPGA烧录实现

 配置确认引脚,烧录程序(可参考之前的FPGA文件,有详细记录每一步操作,这里就给出关键操作截图)

 烧录效果:

【博客调用】状态机思想实习流水灯

二、CPLD和FPGA芯片

CPLD(Complex Programmable Logic Device,复杂可编程逻辑器件)和FPGA(Field-Programmable Gate Array,现场可编程门阵列)是可编程逻辑器件的两大分支,它们在结构、性能和应用场景上有显著差异。

1. 核心结构与技术原理

特性CPLDFPGA
逻辑单元基于**乘积项(Product-Term)**结构,包含与阵列和或阵列,逻辑块较大且固定。基于**查找表(LUT)**结构,每个LUT(如4/6输入)模拟任意组合逻辑,逻辑块细粒度。
互连资源全局总线式互连,延迟固定且确定性高分布式可编程互连,延迟可变但灵活性高
存储技术非易失性(如Flash/EEPROM),配置掉电保留。易失性(SRAM为主),需外部配置芯片(如Flash)存储代码。
触发器数量较少,适合组合逻辑为主的设计。大量触发器,支持复杂时序逻辑。

2. 性能与容量

指标CPLDFPGA
逻辑规模较小(数百至数千逻辑门)大(数万至数百万逻辑门)
运行速度高(固定延迟,适合高速控制)中高(依赖布线优化,适合并行计算)
功耗低(静态功耗为主)中高(动态功耗显著,尤其高频场景)
配置时间毫秒级(非易失性,上电即用)秒级(需从外部加载配置)

3. 适用场景

场景CPLDFPGA
简单控制逻辑电源管理、接口转换、总线桥接。不适用(资源浪费)。
复杂算法处理不适用(容量不足)。图像处理、通信协议(如5G)、AI推理。
确定性时序需求高(如电机控制、工业PLC)。低(时序受布线影响)。
原型验证不适用。高(可快速迭代设计)

4. 选型建议

  • 选择CPLD

    • 需要非易失性存储,上电即用。

    • 设计简单(如组合逻辑、小型状态机)。

    • 对功耗敏感(电池供电设备)。

  • 选择FPGA

    • 处理复杂算法(如FFT、卷积运算)。

    • 需要动态重构(如通信协议切换)。

    • 高并行性需求(如数据中心加速)。

三、HDLbitsFPGA练习记录(combinational logic)

练习点击这里:HDLBitshttps://hdlbits.01xz.net/wiki/Main_Page

 实验记录:

练习一:7420chip

7400 系列集成电路是一系列每个都包含几个门电路的数字芯片。7420 是一种包含两个 4 输入 NAND 门的芯片。
创建一个具有与 7420 芯片相同功能的模块。该模块有 8 个输入和 2 个输出。

分析:

  • 每个 4 输入的 NAND 门的逻辑功能是:当所有输入都为 1 时,输出为 0;否则,输出为 1。
  • 每个 4 输入 NAND 门的输入是4个输入信号,输出是 1 个信号。

代码:

module top_module ( 
    input p1a, p1b, p1c, p1d,
    output p1y,
    input p2a, p2b, p2c, p2d,
    output p2y );
	assign p1y=~(p1a&p1b&p1c&p1d);
    assign p2y=~(p2a&p2b&p2c&p2d);
endmodule

 仿真电路图;

练习二:电路描述

电路 B 可以通过以下模拟波形来描述:

代码:

module top_module ( input x, input y, output z );
	assign z = ~(x ^ y);
endmodule

仿真图:

 练习三、多路选择器1-9

设计一个 16 位宽、9 对 1 的多路复用器。当 sel=0 时选择 a,当 sel=1 时选择 b,以此类推。对于未使用的模式(sel=9 到 15),将所有输出位都设置为 '1'。

代码如下:

module top_module (
    input [15:0] a,
    input [15:0] b,
    input [15:0] c,
    input [15:0] d,
    input [15:0] e,
    input [15:0] f,
    input [15:0] g,
    input [15:0] h,
    input [15:0] i,
    input [3:0] sel,
    output logic [15:0] out
);

    // Case语句只能用在过程性块(always块)中
    // 这是一个组合逻辑电路,所以使用组合逻辑的always @(*)块。
    always @(*) begin
        out = '1;    // '1 是一种特殊的字面量语法,表示所有位都为1的数。
                     // '0、'x 和 'z 也是有效的。
                     // 给 'out' 赋一个默认值,
        case (sel)
            4'h0: out = a;
            4'h1: out = b;
            4'h2: out = c;
            4'h3: out = d;
            4'h4: out = e;
            4'h5: out = f;
            4'h6: out = g;
            4'h7: out = h;
            4'h8: out = i;
        endcase
    end
    
endmodule

 仿真波形图:

 

练习四:Full adder

创建一个全加器。全加器接收三个位(包括进位输入)并输出和以及进输出。位

预期的解决方案长度:约 2 行。

代码:

module top_module (
    input a,         // 输入位a
    input b,         // 输入位b
    input cin,       // 进位输入
    output sum,      // 和输出
    output cout      // 进位输出
);

    assign {cout, sum} = a + b + cin;  // 使用加法运算直接计算和与进位

endmodule

代码解释

  1. 模块接口

    • input ainput b:两个加数位。

    • input cin:进位输入(来自低位的进位)。

    • output sum:加法结果的和。

    • output cout:进位输出(用于更高位的加法)。

  2. 逻辑实现

    • 使用 assign 语句实现组合逻辑。

    • a + b + cin:直接对三个输入位进行加法运算。

    • {cout, sum}:将加法结果的高位赋值给 cout(进位输出),低位赋值给 sum(和输出)。

 练习五、Bcdadd4

您将获得一个名为 bcd_fadd 的 BCD(二进制编码十进制)一位数加法器,它能将两个 BCD 数字以及进位输入相加,并生成和以及进位输出。

module bcd_fadd (
    input [3:0] a,
    input [3:0] b,
    input     cin,
    output   cout,
    output [3:0] sum );

实例化 4 个 bcd_fadd 模块以创建一个 4 位 BCD 溪流进位加法器。您的加法器应将两个 4 位 BCD 数字(打包成 16 位向量)和一个进位输入相加,以产生一个 4 位和进位输出。

代码:

module top_module (
    input [15:0] a, b,  // 输入的两个 4 位 BCD 数字,打包成 16 位向量
    input cin,         // 进位输入
    output cout,       // 进位输出
    output [15:0] sum  // 4 位 BCD 和,打包成 16 位向量
);

    // 中间进位信号,用于连接各个 BCD 加法器
    wire c1, c2, c3;  

    // 实例化 4 个 bcd_fadd 模块
    bcd_fadd fa0 (
        .a(a[3:0]),      // 第一个 BCD 数字的最低位
        .b(b[3:0]),      // 第二个 BCD 数字的最低位
        .cin(cin),       // 进位输入
        .cout(c1),       // 输出到下一个加法器的进位
        .sum(sum[3:0])   // 第一个 BCD 位的和
    );

    bcd_fadd fa1 (
        .a(a[7:4]),      // 第一个 BCD 数字的次低位
        .b(b[7:4]),      // 第二个 BCD 数字的次低位
        .cin(c1),        // 从上一个加法器传来的进位
        .cout(c2),       // 输出到下一个加法器的进位
        .sum(sum[7:4])   // 第二个 BCD 位的和
    );

    bcd_fadd fa2 (
        .a(a[11:8]),     // 第一个 BCD 数字的次高位
        .b(b[11:8]),     // 第二个 BCD 数字的次高位
        .cin(c2),        // 从上一个加法器传来的进位
        .cout(c3),       // 输出到下一个加法器的进位
        .sum(sum[11:8])  // 第三个 BCD 位的和
    );

    bcd_fadd fa3 (
        .a(a[15:12]),    // 第一个 BCD 数字的最高位
        .b(b[15:12]),    // 第二个 BCD 数字的最高位
        .cin(c3),        // 从上一个加法器传来的进位
        .cout(cout),     // 最终的进位输出
        .sum(sum[15:12]) // 第四个 BCD 位的和
    );

endmodule

 练习结果仿真图:

 

四、总结

本次实验完成了,收获颇丰,进一步掌握状态机思想,又一次复习了仿真操作,对FPGA的掌握更上一层楼。还学会了使用HDLbits 用来模拟仿真波形图,很是方便。在这个在线网站上也可以自己做题,理解底层电路设计的更多知识,收获很大,这是本人实验时候的一个记录过程,希望与大家共勉!

另外,本人才疏学浅,要是有错误的地方,还望大家海涵,感谢您的阅读!

参考文献:

什么是状态机(Finite-state machine)?-CSDN博客

FPGA学习(四)——状态机重写LED流水灯并仿真-CSDN博客

Quartus使用步骤及联合Modelsim仿真教程_quartus仿真-CSDN博客

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_hdlbits网站中文版-CSDN博客

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

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

相关文章

Android 中集成 Unity 工程的步骤

在 Adroid 项目中集成 Unity 工程,主要步骤如下: 一、前提条件 1、已有一个 Android 工程项目; 2、Unity 工程已导出为 Android 工程,目录大概如下: 二、集成步骤 1、在 Android 工程中导入 Unity 工程的 unityLibrary 模块。 在 Android Studio 中,点击菜单栏 Fil…

Python从入门到精通全套视频教程免费

概述 &#x1f4e2; 所有想学Python的小伙伴看过来&#xff01;作为深耕编程领域的技术分享者&#xff0c;最新整理了一份Python从0到1的视频教程。 &#x1f4a1;亮点 ✅ 保姆级系统路线&#xff1a;从环境搭建、语法精讲&#xff0c;到爬虫/数据分析/AI/Web全栈开发&#…

蓝桥杯:对字符串处理常用知识笔记

一、前面四个是计算带有空格字符串的的长度计算 C语言代码 #include<string.h> #include<stdio.h> int main() { char s[105]; gets(s); printf("%d", strlen(s)); return 0; } 算法2 C 代码&#xff08;常用&#xff09; #include <iostream> #in…

实现一个 Markdown 编辑器组件:Vue 3 + Vite + Highlight.js

文章目录 一、项目背景与需求分析二、搭建基础项目1. 初始化 Vue 3 项目2. 安装依赖 三、实现 Markdown 编辑器组件1. 创建 Markdown 编辑器组件2. 组件说明 四、优化与拓展1. 自动保存功能2. 文件上传功能 五、总结 一、项目背景与需求分析 在现代前端开发中&#xff0c;Mark…

帆软fvs文件中某表格新增数据来声提醒

1.上传音频文件到帆软安装目录的指定环境 准备一个音频文件&#xff08;如 mp3 格式&#xff09;&#xff0c;并将其放置在合适的目录。 例如&#xff1a;%FR_HOME%\webapps\webroot\help 2.点击 FVS 模板左上角「模板>页面加载结束事件」&#xff0c;输入以下 JavaScript …

从零用java实现 小红书 springboot vue uniapp (11)集成AI聊天机器人

前言 移动端演示 http://8.146.211.120:8081/#/ 管理端演示 http://8.146.211.120:8088/#/ 项目整体介绍及演示 前面的文章我们主要完成了基础模块的开发 这次我们跟一下热点 创建AI聊天机器人 并嵌入到我们的uniapp中 首先需要了解dify我已经完成了搭建win10 VMware安装ubuntu…

$_POST 超级全局变量

$_POST 是一个超级全局变量&#xff0c;在 PHP 中用于收集通过 HTTP POST 方法发送到服务器的数据。与 $_GET 不同&#xff0c;$_POST 允许发送大量数据&#xff0c;且数据不会显示在 URL 中&#xff0c;因此更适用于提交敏感信息&#xff0c;如用户登录信息、表单数据等。 使…

开发一个环保回收小程序需要哪些功能?环保回收小程序

废品分类展示与识别 详细分类列表&#xff1a;清晰展示常见废品类型&#xff0c;如废纸&#xff08;报纸、书本纸、包装纸等&#xff09;、塑料&#xff08;塑料瓶、塑料容器、塑料薄膜等&#xff09;、金属&#xff08;易拉罐、铁制品、铜制品等&#xff09;、玻璃&#xff0…

Debezium嵌入式连接postgresql封装服务

文章目录 1.项目结构&#xff1a;2.依赖&#xff1a;3.application.properties4.DebeziumConnectorConfig类5.TableEnum类6.TableHandler接口&#xff08;表处理抽象&#xff09;7.DefaultTableHandler默认实现类8.UserTableHandler处理类9.TableHandlerFactory工厂10.Debezium…

Python 爬取 1688.item_get_factory 接口:获取工厂档案信息实战指南

在电商采购和供应链管理中&#xff0c;了解供应商的工厂信息是至关重要的一步。1688 作为国内领先的 B2B 平台&#xff0c;提供了丰富的供应商和工厂档案信息。通过 item_get_factory API 接口&#xff0c;开发者可以获取工厂的详细信息&#xff0c;包括工厂名称、地址、联系方…

Rust所有权详解

文章目录 Rust所有权所有权规则作用域 内存和分配移动与克隆栈空间堆空间 关于函数的所有权机制作为参数作为返回值 引用与租借垂悬引用 Rust所有权 C/C中我们对于堆内存通常需要自己手动管理&#xff0c;手动申请和释放&#xff0c;即便有了智能指针&#xff0c;对于效率的影…

CExercise_07_1指针和数组_2数组元素的逆序数组逆序(指针版 reverse_by_ptr 和下标版 reverse_arr)

题目&#xff1a; 数组元素的逆序。要求使用[]运算符以及纯粹指针操作两种方式来完成。 关键点 arr[i] arr[len - 1 - i]; arr[0]arr[len-1]; 如果数组序列是偶数,则调换最中间一对为止;若为奇数,则单出一个不用反转. 思想就是长度取一半 eg:8/2, 9/24.5,反转一半,到5时固定…

框架PasteForm实际开发案例,换个口味显示数据,支持echarts,只需要标记几个特性即可在管理端显示(2)

PasteForm框架的主要思想就是对Dto进行标记特性,然后管理端的页面就会以不一样的UI呈现 使用PasteForm框架开发,让你免去开发管理端的烦恼,你只需要专注于业务端和用户端! 在管理端中,如果说表格是基本的显示方式,那么图表chart就是一个锦上添花的体现! 如果一个项目拥…

Starrocks的Bitmap索引和Bloom filter索引以及全局字典

写这个的主要作用是梳理一下Starrocks的索引效率以及使用场景。 Starrocks Bitmap索引 原理&#xff1a; Bitmap 索引是一种使用 bitmap 的特殊数据库索引。bitmap 即为一个 bit 数组&#xff0c;一个 bit 的取值有两种&#xff1a;0 或 1。 每一个 bit 对应数据表中的一行&…

QML面试笔记--UI设计篇05容器控件

1. QML中容器控件全解&#xff1a;构建灵活界面的基石 1.1. Item&#xff08;万物容器&#xff09;1.2. Rectangle&#xff08;视觉容器&#xff09;1.3. ListView&#xff08;动态列表容器&#xff09;1.4. Frame&#xff08;表单容器&#xff09;1.5. SwipeView&#xff08;页…

VSCode运行,各类操作缓慢,如何清理

VSCode写代码&#xff0c;随着项目逐步进展&#xff0c;代码量在增加&#xff0c;依赖的第三方头文件也在增加&#xff0c; 先是发现代码提示的速度变慢&#xff0c; 后来格式化代码速度太慢 然后c/c代码的语法检查有时候压根就失败&#xff0c;来个错误提示 还有source contro…

redis(2)-mysql-锁

1.数据倾斜&#xff1a; 解决&#xff1a;虚拟节点 2.缓存穿透&#xff1a;缓存雪崩、击穿 3.分布式锁 多把锁控制不同节点上的一致性问题。 锁是有失效时间的。 强制回收。 4.redis 和zookeeper的区别 redis 数据支持有效期 4.1 zookeeper 分布式一致性服务框架&am…

OpenLayers:海量图形渲染之矢量切片

最近由于在工作中涉及到了海量图形渲染的问题&#xff0c;因此我开始研究相关的解决方案。在咨询了许多朋友之后发现矢量切片似乎是行业内最常用的一种解决方案&#xff0c;于是我便开始研究它该如何使用。 一、什么是矢量切片 矢量切片按照我的理解就是用栅格切片的方式把矢…

AI智算-K8s+vLLM Ray:DeepSeek-r1 671B 满血版分布式推理部署实践

K8s + vLLM & Ray:DeepSeek-r1 671B 满血版分布式推理部署实践 前言环境准备1. 模型下载2. 软硬件环境介绍正式部署1. 模型切分2. 整体部署架构3. 安装 LeaderWorkerSet4. 通过 LWS 部署DeepSeek-r1模型5. 查看显存使用率6. 服务对外暴露7. 测试调用API7.1 通过 curl7.2 通…

深入浅出SPI通信协议与STM32实战应用(W25Q128驱动)(实战部分)

1. W25Q128简介 W25Q128 是Winbond推出的128M-bit&#xff08;16MB&#xff09;SPI接口Flash存储器&#xff0c;支持标准SPI、Dual-SPI和Quad-SPI模式。关键特性&#xff1a; 工作电压&#xff1a;2.7V~3.6V分页结构&#xff1a;256页/块&#xff0c;每块16KB&#xff0c;共1…