加载中…
个人资料
nxhsyv
nxhsyv
  • 博客等级:
  • 博客积分:0
  • 博客访问:6,040
  • 关注人气:8
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

同步有限状态机示例2(2段式)

(2019-12-29 21:56:38)
分类: 状态机
状态迁移图:
同步有限状态机示例2(2段式)

1、fsm_1.v
 fsm_1.v
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
module fsm_1(
    input   wire            sclk,
    input   wire            rst_n,
    input   wire            write_start,

    output  wire            error_flag
);

parameter   IDLE    5'b00001; //state[0] 
parameter   WRITE   5'b00010; //state[1] 
parameter   READ    5'b00100; //state[2] 
parameter   CHECK   5'b01000; //state[3] 
parameter   ERROR   5'b10000; //state[4] 

reg     [4:0  state; //状态指示,独热码
reg             write_end;
reg     [9:0  write_cnt;
reg             read_end;
reg     [9:0  read_cnt;

/
//第1段:状态迁移描述(对state的赋值)单独写在一个always块
always @(posedge sclk or negedge rst_n) begin
    if(rst_n == 1'b0)
        state <= IDLE;
    else begin //begin...end间的语句也是并行执行的
        case(state) //状态机使用case语句描述,而不能使用if...else,这是由综合器的特性决定的
            IDLE:
                if(write_start == 1'b1)
                    state <= WRITE;
                //else //时序逻辑对寄存器进行操作,if...else语句在不调用else情况下,寄存器默认保持原来状态。这是由硬件电路中寄存器的结构决定的!
                    //state <= state; //时钟触发情况下,不写else不会生成锁存器。电平触发情况下不写else会生成锁存器。
            WRITE:
                //if(write_cnt == 10'd1023) //if条件内尽量少写多位宽的数据。if条件会转换成查找表,查找表是组合逻辑实现的基本单元。当组合逻辑路径较长时会导致延时较大,造成时序紧张。
                if(write_end == 1'b1) //用write_end标志替代多位宽判断条件
                    state <= READ;
            READ:
                if(read_end == 1'b1)
                    state <= CHECK;
            CHECK:
                if(((|write_cnt) == 1'b0) &&((|read_cnt) == 1'b0)) //write_cnt==1023
                    state <= IDLE;
                else
                    state <= ERROR;
            ERROR:
                state <= ERROR;
            default:
                state <= IDLE; //使状态机不至于锁死
        endcase 
    end 
end
    
//第2段:描述状态机输出
assign error_flag state[4];

/
//写状态控制相关变量
always @(posedge sclk or negedge rst_n) begin
    if(rst_n == 1'b0)
        write_cnt <= 'd0;
    else if(state == WRITE) //综合工具会优化为 else if(state[0] == WRITE)
        write_cnt <= write_cnt 1'b1;
    else
        write_cnt <= 'd0;
end
        
always @(posedge sclk or negedge rst_n) begin
    if(rst_n == 1'b0)
        write_end <= 1'b0;
    else if(write_cnt == 'd1022) //多位宽可以省去10'd1022 
        write_end <= 1'b1;
    else
        write_end <= 1'b0;
end        
        
//读状态控制相关变量        
always @(posedge sclk or negedge rst_n) begin
    if(rst_n == 1'b0)
        read_cnt <= 'd0;
    else if(state == READ)
        read_cnt <= read_cnt 1'b1;
    else
        read_cnt <= 'd0;
end        
        
always @(posedge sclk or negedge rst_n) begin
    if(rst_n == 1'b0)
        read_end <= 1'b0;
    else if(read_cnt == 'd1022)
        read_end <= 1'b1;
    else
        read_end <= 1'b0;
end

endmodule
 
2、sim目录下tb_fsm_1.v
tb_fsm_1.v 
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
//------------------------------------------
//*1、仿真时常用force语句对信号进行强制赋值。
//------------------------------------------
`timescale 1ns/1ps
module tb_fsm_1();
reg         sclk_i;
reg         rst_n_i;
reg         write_start_i;
wire        error_flag_i;

initial begin
    sclk_i 0;
    rst_n_i 0;
    #100;
    rst_n_i 1;
end 

initial begin
    write_start_i 0;
    #300;
    write_start_i 1;
    #30;
    write_start_i 0;

end 

//force 强制赋值语句
initial begin
    #41280;
    force fsm_1_inst.read_cnt 10'd2; //在check状态对例化模块fsm_1_inst内部的信号read_cnt强制赋值,迫使状态机进入Error状态
end 

always #10 sclk_i ~sclk_i;

fsm_1 fsm_1_inst(
    .sclk       (sclk_i         ),
    .rst_n      (rst_n_i        ),
    .write_start(write_start_i  ),
    .error_flag (error_flag_i   )
);

endmodule

3、run.do
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
###############################################################
#1、do文件的注释是由“#”开始的,但不可以在代码行后面添加,只能另起一行。
#2、使用virtual type {...} 定义新的结构体类型,可将模块内部信号强制转换成这种类型
#3、使用 “-color xxx” 关键字将添加的信号转为某种延时显示
#
#################################################################
quit -sim
vlib work

vlog ./tb_fsm_1.v
vlog ./../design/*.v

vsim -voptargs=+acc work.tb_fsm_1

Modelsim中对于状态机状态的描述可以是数字形式,如00001/00010/00100等。也可在.do文件中将其转化成字符形式显示,如IDLE、WRITE、READ等。
#定义一个新的虚拟结构体数据类型,并将其命名为virtual_new_signal。注意“type”关键字和“{”之间、“}”前面都要有空格
#将十六进制的01转换为IDLE显示,02转换为WRITE显示...
virtual type {
    {01 IDLE}
    {02 WRITE}
    {04 READ}
    {08 CHECK}
    {10 ERROR}
virtual_new_signal

#把模块内的state信号强制转换成virtual_new_signal类型,并将其重新命名为new_state
virtual function {(virtual_new_signal)tb_fsm_1/fsm_1_inst/state} new_state

#添加新的new_state信号,将其显示位红色
add wave -color red tb_fsm_1/fsm_1_inst/new_state

#tb_fsm_1是文件tb_fsm_1.v内的顶层模块名,fsm_1_inst是模块tb_fsm_1内部例化的模块名
add wave tb_fsm_1/fsm_1_inst/*   

run 100us


0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有