FPGA入门学习Day0——状态机相关内容解析HDLbits练习

目录

一、状态机简单介绍

(一)状态机的核心要素

(二)状态机的类型

(三)状态机的设计步骤

(四)状态机的应用要点

二、实现LED流水灯及其仿真

(一)流水灯代码

(二)modesim仿真

(三)结果展示

1、modesim仿真结果

2、硬件结果

[三、 CPLD芯片介绍及与FPGA芯片进行对比](#三、 CPLD芯片介绍及与FPGA芯片进行对比)

[(一) CPLD芯片简介](#(一) CPLD芯片简介)

(二)CPLD和FPGA芯片主要技术区别

[1. 结构与逻辑容量](#1. 结构与逻辑容量)

[2. 配置技术与易失性](#2. 配置技术与易失性)

[3. 时序特性与时钟管理](#3. 时序特性与时钟管理)

[4. 功耗与成本](#4. 功耗与成本)

[5. 适用场景](#5. 适用场景)

四、HDLbitsFPGA组合逻辑题目训练

(一)创建一个半加器

(二)创建一个全加器

(三)创建一个或门运算

(四)创建一个4位BCD码加法器

(五)创建一个2对1多路复用器

(六)创建一个2对1总线多路复用器

五、总结


一、状态机简单介绍

(一)状态机的核心要素

  1. 状态(State)

    系统在任意时刻只能处于其中一个预设的状态。例如,交通灯控制器可能包含"红灯""绿灯""黄灯"三种状态。每个状态代表系统的一种特定行为模式。

  2. 转移条件(Transition Condition)

    状态之间的切换由事件或条件触发。例如,当倒计时结束时,交通灯从"绿灯"转移到"黄灯"。转移条件可以是外部输入(如按键信号)或内部逻辑(如计数器溢出)。

  3. 动作(Action)

    在进入、离开或保持某一状态时执行的操作。例如,进入"绿灯"状态时启动倒计时,离开时关闭当前灯。

(二)状态机的类型

1、Moore型状态机

输出仅依赖于当前状态,与输入无关。例如,交通灯的亮灯逻辑完全由当前状态决定,与外部输入(如车辆检测信号)无关。其特点是输出稳定,但灵活性较低。

特点

  • 输出仅取决于当前状态
  • 时序逻辑输出,稳定性更好
  • 典型应用:模式识别、定时控制

2、Mealy型状态机

输出由当前状态和输入共同决定。例如,自动售货机在投币后根据金额和当前状态决定是否出货或找零。这种类型能更灵活地响应输入,但输出可能因输入变化而产生瞬时波动。

特点

  • 输出由当前状态和输入共同决定
  • 组合逻辑输出,响应更快
  • 典型应用:通信协议、实时控制

(三)状态机的设计步骤

1、需求分析

明确系统的所有可能状态、触发条件和预期动作。例如,流水灯系统需要定义四个状态(每个LED亮起),并确定切换的时间间隔。

2、绘制状态转移图

用图形化工具(如UML状态图)表示状态、转移条件和动作。例如,用箭头连接S0→S1→S2→S3→S0,标注转移条件为计时器溢出。

3、状态编码

为每个状态分配唯一的二进制编码。例如,S0=00、S1=01、S2=10、S3=11。编码需考虑资源优化和可扩展性。

4、代码实现

使用硬件描述语言(如Verilog)描述状态转移和输出逻辑。常见的实现方式分为以下三种:

  • 一段式:将所有逻辑(状态转移、输出)放在单个时序块中。代码紧凑但可维护性差,适合简单逻辑。
  • 二段式:用时序逻辑处理状态转移,组合逻辑处理输出和条件判断。可读性高,但输出可能存在毛刺。
  • 三段式:独立时序块处理状态转移、组合逻辑判断条件、另一时序块生成输出。资源消耗稍高,但输出稳定且易于维护。

5、验证与调试

通过仿真覆盖所有状态路径,确保逻辑正确;硬件验证时需检查实际时序和物理信号。

(四)状态机的应用要点

  1. 复杂度管理

    状态机通过模块化设计,将复杂逻辑分解为独立状态,降低系统整体复杂度。例如,通信协议解析器可划分为"空闲""接收头""接收数据""校验"等状态。

  2. 可读性与维护性

    状态转移图直观展示逻辑流程,便于团队协作和后期修改。相比之下,嵌套的 if-else 语句在扩展时易引入错误。

  3. 硬件实现优化

    明确的状态编码和分离的组合/时序逻辑,有助于综合工具生成高效电路。避免冗余逻辑(如未使用的状态)可节省FPGA资源。

  4. 抗干扰设计

    添加"默认状态"处理未定义状态,防止系统锁死;关键路径添加时序约束,确保信号稳定。

二、实现LED流水灯及其仿真

(一)流水灯代码

复制代码
module LS_LED(
    input          clk,
    input          rst_n,
    input          pause_sw,
    output reg [5:0] led
);

// 仿真时使用较小的计数值,实际部署时改为50_000_000
`ifdef SIMULATION
    parameter T = 50;       // 仿真时缩短计数周期
`else
    parameter T = 50_000_000; // 实际硬件运行时1秒定时
`endif

// 使用独热码(one-hot)编码状态,提高可读性
typedef enum logic [5:0] {
    STATE_LED0 = 6'b000001,
    STATE_LED1 = 6'b000010,
    STATE_LED2 = 6'b000100,
    STATE_LED3 = 6'b001000,
    STATE_LED4 = 6'b010000,
    STATE_LED5 = 6'b100000
} state_t;

state_t cstate, nstate;  // 使用枚举类型定义状态
reg [25:0] cnt;          // 26位计数器

// 三段式状态机实现

// 第一段:状态寄存器更新
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cstate <= STATE_LED0;
        cnt <= 0;
    end
    else begin
        if (!pause_sw) begin
            if (cnt == T - 1) begin
                cnt <= 0;
                cstate <= nstate;
            end
            else begin
                cnt <= cnt + 1;
            end
        end
        // 暂停时保持当前状态和计数值
    end
end

// 第二段:次态逻辑
always @(*) begin
    case (cstate)
        STATE_LED0: nstate = (cnt == T - 1) ? STATE_LED1 : STATE_LED0;
        STATE_LED1: nstate = (cnt == T - 1) ? STATE_LED2 : STATE_LED1;
        STATE_LED2: nstate = (cnt == T - 1) ? STATE_LED3 : STATE_LED2;
        STATE_LED3: nstate = (cnt == T - 1) ? STATE_LED4 : STATE_LED3;
        STATE_LED4: nstate = (cnt == T - 1) ? STATE_LED5 : STATE_LED4;
        STATE_LED5: nstate = (cnt == T - 1) ? STATE_LED0 : STATE_LED5;
        default:    nstate = STATE_LED0;
    endcase
end

// 第三段:输出逻辑
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        led <= STATE_LED0;
    end
    else begin
        led <= cstate;  // 状态直接映射到LED输出
    end
end

endmodule

测试代码:

复制代码
`timescale 1ns / 1ps

module LS_LED_tb;

    // 输入信号
    reg clk;
    reg rst_n;
    reg pause_sw;

    // 输出信号
    wire [5:0] led;

    // 生成50MHz时钟
    initial begin
        clk = 0;
        forever #10 clk = ~clk; // 50MHz时钟周期20ns
    end

    // 实例化被测模块
    LS_LED uut(
        .clk(clk),
        .rst_n(rst_n),
        .pause_sw(pause_sw),
        .led(led)
    );

    // 测试流程
    initial begin
        // 初始化
        rst_n = 0;
        pause_sw = 1; // 初始暂停
        #100;
        
        // 测试1: 复位释放
        rst_n = 1;
        #100;
        
        // 测试2: 正常流水灯效果
        pause_sw = 0;
        #5000; // 观察多个状态转换
        
        // 测试3: 暂停功能
        pause_sw = 1;
        #1000;
        
        // 测试4: 恢复运行
        pause_sw = 0;
        #3000;
        
        // 测试5: 复位功能
        rst_n = 0;
        #50;
        rst_n = 1;
        #100;
        
        $display("Simulation complete");
        $finish;
    end

    // 波形记录
    initial begin
        $dumpfile("ls_led.vcd");
        $dumpvars(0, LS_LED_tb);
    end

endmodule

(二)modesim仿真

  • 生成.vt文件

点击Processing→Start→Start test bench template writer,便生成了对应的.vt文件。

  • 修改.vt文件内容为测试代码

在quartus界面中打开,随后将测试代码写入其中并保存

  • 然后对仿真文件设置点击Assignments→Settings,再点击下面的Simulation按照如图设置
  • 然后浏览刚才的.vt文件,最后点击Add添加达到如下图效果,再点击OK即可。
  • 随后回到初始界面点击下图按钮进行仿真得到流水灯的仿真结果

(三)结果展示

1、modesim仿真结果

2、硬件结果

FPGA流水灯0.0

三、 CPLD芯片介绍及与FPGA芯片进行对比

(一) CPLD芯片简介

CPLD(复杂可编程逻辑器件)是基于EEPROM/Flash的非易失性半定制数字电路,集成可编程逻辑块、互连矩阵和I/O单元,具备确定时序、低功耗、上电即用特性。较FPGA规模小(数百至万门级)但延迟固定且无需外置配置芯片,专用于接口协议转换(如UART/SPI)、状态机控制及信号处理,是嵌入式系统胶合逻辑核心,开发通过HDL设计、仿真至JTAG烧录完成,代表型号包括Xilinx CoolRunner和Altera MAX系列。

(二)CPLD和FPGA芯片主要技术区别

1. 结构与逻辑容量

  • CPLD

    基于乘积项(与或阵列)结构,内部逻辑单元通过固定互连资源连接,逻辑容量较小(通常为千门级)。其核心模块包括可编程逻辑模块(PLM)和寄存器阵列(PRA),适合实现简单的组合逻辑和时序逻辑,如状态机、接口控制等。

  • FPGA

    采用查找表(LUT)和可编程互连结构,逻辑单元(CLB)与片上存储(Block RAM)、DSP模块等高度灵活组合,逻辑容量可达百万门级。FPGA的资源动态分配能力使其能够实现复杂算法(如FFT、卷积运算)和高并行任务。

2. 配置技术与易失性

  • CPLD

    使用非易失存储器(如EEPROM或Flash)存储配置信息,上电后自动加载,无需外部配置芯片。配置速度快,但无法实时修改设计。

  • FPGA

    依赖SRAM存储配置数据,断电后信息丢失,需外接配置芯片(如Flash)。支持动态重配置(部分型号),允许运行时更新逻辑功能,灵活性更高。

3. 时序特性与时钟管理

  • CPLD

    时序延迟固定,时钟管理简单,适用于对确定性延时要求高的场景(如实时控制)。

  • FPGA

    时序路径依赖布局布线结果,需通过约束文件优化关键路径。提供锁相环(PLL)、时钟分频器等复杂时钟管理模块,适合高频、高精度时序设计(如高速通信协议)。

4. 功耗与成本

  • CPLD

    静态功耗低,整体功耗较小,适合电池供电或低功耗场景。成本较低,适合中小规模设计。

  • FPGA

    逻辑资源丰富导致静态功耗较高,动态功耗随逻辑复杂度增加而显著上升。成本高于CPLD,但性能与灵活性优势明显。

5. 适用场景

  • CPLD
    控制密集型应用 :电源管理、接口转换、简单协议实现(如UART、SPI)。
    特点:上电即运行、低延迟、设计周期短。

  • FPGA
    计算密集型应用 :数字信号处理(DSP)、图像处理、高速通信(如PCIe、以太网)。
    特点:并行计算能力强、支持复杂算法、可重构性高。

四、HDLbitsFPGA组合逻辑题目训练

(一)创建一个半加器

半加器实现两个二进制数相加,输出和与进位,无进位输入。

题目介绍:

答案代码:

复制代码
module top_module( 
    input a, b,
    output cout, sum );

endmodule

关键点解析:

1、功能 :实现两个1位二进制数(ab)的加法运算。

2、逻辑规则

  • 和(sum):由a^b(异或)计算,结果为两数相加的本位值。
  • 进位(cout):由a&b(与)计算,当两数均为1时进位为1。

系统生成仿真图:

(二)创建一个全加器

全加器将三个一位二进制数相加,输出和及进位。

题目介绍:

答案代码:

复制代码
module top_module(
    input a, b, cin,
    output cout, sum );

    assign sum = a ^ b ^ cin;         // 全加器求和逻辑
    assign cout = (a & b) | (a & cin) | (b & cin); // 进位生成逻辑
endmodule

关键点解析

1、功能:实现三个1位二进制数(a、b和进位Cin)的加法运算。

2、逻辑规则

  • 和(sum):由a ^ b ^ Cin 计算,结果为三数相加的本位值(奇偶校验逻辑)。
  • 进位(cout):若任意两个输入为1(a & b、a & Cin或b & Cin),则产生进位。

系统生成仿真图:

(三)创建一个或门运算

或门电路实现逻辑或操作,当任一输入为高电平时输出高电平,全低则输出低电平。

题目介绍:

答案代码:

复制代码
module top_module (
    input in1,
    input in2,
    output out);

    assign out = in1 & in2;  // 实现与门逻辑,输出为输入信号的逻辑与
endmodule

关键点解析

1、功能:实现两个1位二进制输入(in1和in2)的逻辑与操作。

2、逻辑规则

  • 输出 out 仅在 in1 和 in2 同时为 1 时输出 1,否则输出 0

系统生成仿真图:

(四)创建一个4位BCD码加法器

四位BCD码加法器用于两个十进制数的相加,通过两个4位二进制加法器实现。若相加结果超过9或产生进位,则加6校正并进位,确保结果符合BCD编码规则,适用于精确十进制运算。

题目介绍:

答案代码:

复制代码
module top_module (
    input [15:0] a, b,
    input cin,
    output cout,
    output [15:0] sum );

    wire c1, c2, c3; // 中间进位信号
    
    // 实例化四个BCD加法器,级联进位
    bcd_fadd add0 ( .a(a[3:0]),   .b(b[3:0]),   .cin(cin),  .cout(c1), .sum(sum[3:0])  );
    bcd_fadd add1 ( .a(a[7:4]),   .b(b[7:4]),   .cin(c1),   .cout(c2), .sum(sum[7:4])  );
    bcd_fadd add2 ( .a(a[11:8]),  .b(b[11:8]),  .cin(c2),   .cout(c3), .sum(sum[11:8]) );
    bcd_fadd add3 ( .a(a[15:12]), .b(b[15:12]), .cin(c3),   .cout(cout), .sum(sum[15:12]));
    
endmodule

关键点解析

1、输入与输出

  • **a[15:0] 和 b[15:0]:**16位BCD输入,每4位代表一个 十进制数字(如 a[3:0] 表示个位,a[7:4]表示十位,依此类推)。
  • **sum[15:0]:**16位BCD输出,格式与输入相同,每个4位段为对应十进制位的和。

2、级联结构

  • 通过中间进位信号c1、c2、c3 将4个bcd_fadd模块级联,依次计算个位→十位→百位→千位。

  • 进位传递:低位模块的进位输出(如c1)作为高位模块的进位输入(如add1 的 cin)。

3、BCD加法规则

  • 每个bcd_fadd 模块需实现BCD加法逻辑:

    • 对4位输入进行二进制加法。

    • 调整进位:若结果超过 9(即1001),则需 加6校正(0110)并产生进位。

    • 公式:

      temp_sum = a + b + cin; // 二进制加法结果
      sum = (temp_sum > 9) ? temp_sum + 6 : temp_sum; // 加6校正
      cout = (temp_sum > 9) ? 1 : 0; // 进位生成

  • 例如:5+7 = 12,二进制和为 1100(12),但BCD需要表示为 0010(2)并进位1,因此实际操作为 1100+ 0110= 10010,取低4位 0010,进位为1。

4、模块实例化

bcd_fadd 模块接口:

复制代码
module bcd_fadd (
    input [3:0] a, b,  // 4位BCD输入
    input cin,          // 进位输入
    output cout,        // 进位输出
    output [3:0] sum    // 4位BCD和
);

系统生成仿真图:

(五)创建一个2对1多路复用器

2对1多路复用器根据选择信号(sel)从两个输入(a、b)中选择一个输出。sel=0时输出a,sel=1时输出b。

题目介绍:

答案代码:

复制代码
module top_module(
    input a, b, sel,
    output out );

    assign out = sel ? b : a;  // sel=1时选b,否则选a
endmodule

关键点解析

1、功能:通过选择信号 sel 从两个输入(a和b)中选择一个作为输出。

  • 当 sel = 1 时,输出 out = b。

  • 当 sel = 1 时,输出 out = 1。

2、逻辑规则

  • 使用条件运算符?: 实现选择逻辑,等效于以下逻辑表达式:

    out = (sel & b) | (~sel & a)

系统生成仿真图:

(六)创建一个2对1总线多路复用器

2对1总线多路复用器通过控制信号选择两路N位输入中的一路输出,每比特位均含独立2选1单元,实现并行数据切换,常用于总线系统、数据路由及多通道控制等场景。

题目介绍:

答案代码:

复制代码
module top_module(
    input [99:0] a, b,
    input sel,
    output [99:0] out );

    assign out = sel ? b : a;  // sel=1时选择100位宽的b,否则选a
endmodule

关键点解析:

1、功能 :通过单比特选择信号 sel,从两个100位宽的输入数据 ab 中选择一个作为输出 out

  • sel = 1 时,out 完全等于 b 的100位。

  • sel = 0 时,out 完全等于 a 的100位。

2、逻辑规则

  • 并行选择:每个比特位独立选择,所有100位同时完成选择操作。

  • 等效电路 :由100个独立的2选1多路选择器组成,每个选择器由 sel 信号控制。

系统生成仿真图:

五、总结

在本次FPGA入门学习中,我深刻体会到硬件设计与软件编程的思维差异。通过状态机的三段式设计(状态转移、次态逻辑、输出分离),我不仅掌握了Moore/Mealy型状态机的核心区别,更在实践中感受到模块化设计对复杂逻辑的简化作用------例如LED流水灯项目中,通过独热码编码和计时器控制,直观实现了状态切换与暂停功能,但仿真阶段因计数器位宽设置错误导致时序异常,调试后才理解硬件设计中"精确时序约束"的重要性。

此外,对比CPLD与FPGA时,我意识到芯片选型需紧密结合需求:CPLD的确定性延迟适合实时控制,而FPGA的并行计算能力更适配算法加速。在HDLbits练习中,BCD加法器的"加6校正"逻辑让我初次体会到硬件设计中的"规则映射"思维------并非所有运算都能直接移植软件逻辑,需结合硬件特性调整(如进位链优化)。

未来,我计划深入时序分析与高速接口协议实现,同时加强仿真覆盖率训练,以更系统性地提升FPGA开发能力。

参考博客:FPGA开发基础:详解状态机的类型、设计与实现(附代码示例)-CSDN博客

相关推荐
不可思议迷宫3 小时前
状态机思想编程练习
fpga开发
shock - shock6 小时前
基于高云fpga实现的fir串行滤波器
fpga开发
落笔太慌张~9 小时前
【FPGA基础学习】状态机思想实现流水灯
学习·fpga开发
2202_7544215410 小时前
设计一个UART接口的AXI_LITE_MASTER之一 总体介绍
fpga开发
Abcdsa10 小时前
labview RT FPGA学习心得
fpga开发·labview
肯德基疯狂星期四-V我501 天前
【FPGA】状态机思想实现LED流水灯&HDLbits组合逻辑题训练
fpga开发·verilog·de2-115
乌恩大侠1 天前
【调研】YOLO算法在FPGA/ZYNQ上的部署与加速
yolo·fpga开发
Abcdsa1 天前
labview RT FPGA使用技巧 基础知识
fpga开发·labview
暴富奥利奥1 天前
FPGA学习(四)——状态机重写LED流水灯并仿真
学习·fpga开发