0%

FPGA设计高级技巧之状态机

本节主要介绍了编写状态机时要注意的细节,后续在实际工作中遇到状态机的坑也会在此记录。

状态机的编码方式

  • 具体的编码方式有三种:

    • 顺序码:状态编码遵循传统的状态二进制序列

      image-20240411221917212
    • 格雷码:除了相邻状态编码之间只有一个位变化外,其他和顺序码类似

      image-20240411221940827
    • 独热码:这种方法是在状态机中为每一种状态分配一个触发器。只有一个触发器当前设置有效,其余均设置为无效,故称为“独热”

      image-20240411221954703
  • 假设使用的是格雷码,由于相邻两个数据之间只有一位不同,所以可在很大程度上消除由延时引起的过渡状态。使用格雷码虽然可以大大降低产生过渡状态的概率,但如果当一个状态到下一个状态有多种转换路径时,就不能保证状态跳转时只有一个位变化,这样,将无法发挥格雷码的特点

  • 所以,需要仔细分析状态机的结果,如果状态机中某个状态跳转方向多于一个,此时慎用格雷码,可以采用独热码


多进程状态机

  • 在状态机的描述中,多进程方式使用较多,双进程和三进程描述方式中,三进程描述方式仅仅比双进程多使用了一个进程对状态的输出进行描述

  • 三进程状态机又分为两种,第一种是输出进程使用组合逻辑进行描述;第二种是使用时序逻辑对输出进行描述,其余两个进程完全相同

  • 一般来说,使用寄存器输出可以改变输出的时序条件,还能避免组合电路的毛刺,所以是推荐的描述方式

    image-20240411220452371
  • 上述这种结构可以有效地抑制过渡状态的出现,这是因为输出寄存器只要求状态值在时钟边沿稳定

  • 但是它占用的资源更多,状态机的输出增加了一个时钟周期的延时。但现在逻辑器件的规模越来越大,不在意这一点点资源的消耗,至于输出的延时,对于同步设计来说,都是流水操作,一般不会影响到整个系统的性能


设计综合工具能够识别的状态机

  • 如果使用的是SystemVerilog,一定要使用枚举类型来描述状态机

  • 如果在状态转换逻辑中使用了下例所示的算术运算,那么综合工具将不会识别状态机

    image-20240411221339251
  • 如果将状态变量作为输出,那么综合工具将无法识别状态机

  • 状态机中使用有符号变量,那么综合工具将无法识别状态机


附加知识点

1.modelsim使用run.do脚本仿真

  • 套个模板

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    #run.do文件中#代表注释

    #退出当前仿真功能
    quit -sim
    #清除命令行显示信息
    .main clear

    #vlib为创建库
    vlib ./lib/
    vlib ./lib/work_a/
    vlib ./lib/design/
    #映射逻辑库名,将逻辑库名映射库路径
    vmap base_space ./lib/work_a/
    vmap design ./lib/design/

    #vlog -work代表编译
    vlog -work base_space ./tb_mealy.v
    vlog -work design ./../design/*.v
    #vsim为启动仿真
    #-t 运行仿真的时间精度是ns
    #-L 是链接库关键字
    vsim -t ns -voptargs=+acc -L base_space -L design base_space.tb_mealy

    #用虚拟信号表示状态信息
    virtual type {
    {01 S1}
    {02 S2}
    {04 S3}
    {08 S4}
    {10 S5}
    {20 S6}
    } vir_new_signal

    #add wave用来添加波形
    #-divider用来分组
    add wave -divider {tb_mealy_1}
    add wave tb_mealy/*
    add wave -divider {mealy}
    #顶层/例化的名字/* 其中*号是通配符,匹配所有信号
    add wave tb_mealy/mealy_inst/*
    #创建一个vir_new_signal 类型的信号,也就是把Currt_st进行类型转换
    virtual function {(vir_new_signal)tb_mealy/mealy_inst/Curr_st} new_state
    add wave -color red tb_mealy/mealy_inst/new_state

    run 1us
  • 对应文件夹(在sim文件夹下建一个modelsim工程):

    image-20240306222959762
  • 如果因为-voptargs=+acc报错,见关于 modelsim仿真时出现No objects found matching ‘/*’问题-CSDN博客第一种解决办法即可

  • 浅粘一个仿真结果:

    image-20240306223312601

2.testbench运用task的某写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
task in_data();
integer i;
begin
for (i=0;i<1024;i=i+1)
begin
@(posedge sclk); /****for循环里面包含@(clk),这写法有点意思******/
if(i<50)
in_A=0;
else if(i<200)
in_A=1;
else if(i<700)
in_A=0;
else if(i<800)
in_A=1;
else if(i<900)
in_A=0;
end
end
endtask
欢迎来到ssy的世界