赞
踩
硬件设计需要串行设计思想,而用Verilog描述的电路大多都是并行实现的,但是对于实际的项目工程,往往需要让硬件来做一些具有顺序的工作,这就要用到状态机的思想。状态机简单的来说就是通过不同的状态迁移来完成一些特定的顺序逻辑
以博主浅谈Moore型和Mealy型以及序列检测状态图中的序列检测图为例。
有限状态机:高效的顺序控制模块模型
将所有的逻辑(输入、输出、状态)在一个always块里进行描述,这种写法看起来简单,但对于复杂的状态会容易出错,并且在大型项目中这些代码是不利于维护的。
将时序逻辑和组合逻辑划分开来,时序逻辑进行当前状态和下一状态的切换,组合逻辑实现输入、输出以及状态的判断,这种写法相对容易维护,不过组合逻辑输出容易出现毛刺等问题。
代码易维护,时序逻辑的输出解决了二段式写法中组合逻辑的毛刺问题,但是三段式消耗的资源相对多一点,并且三段式从输入到输出比一段式和二段式会延时一个时钟周期。
输入序列为:010101101 ; 凡收到输入序列101时,输出为1
`timescale 1ns/1ps module fsm_1 ( input clk, //50MHZ input rstn, //复位信号 input data_in, output reg data_out ); //序列检测101--可重叠Moore型--需要四个状态 parameter S0 = 4'b0001, S1 = 4'b0010, S2 = 4'b0100, S3 = 4'b1000; reg [3:0] c_state; //fsm 一段式写法 简单状态机可用,复杂的状态容易出错且不利于维护 always @(posedge clk or negedge rstn) begin if (!rstn) begin c_state <= S0; data_out <= 0; end else case(c_state) S0: begin if(data_in == 1)begin c_state <= S1; data_out <= 0; end else begin c_state <= S0; data_out <= 0; end end S1: begin if(data_in == 0)begin c_state <= S2; data_out <= 0; end else begin c_state <= S1; data_out <= 0; end end S2: begin if(data_in == 1) begin c_state <= S3; data_out <= 0; end else begin c_state <= S0; data_out <= 0; end end S3: begin data_out <= 1; //Moore型状态机,其输出只和S3状态有关 if (data_in == 1) begin c_state <= S1; end else begin c_state <= S2; end end default : begin c_state = S0; end endcase end endmodule
`timescale 1ns/1ps module fsm_1_tb; // Ports reg clk = 0; reg rstn = 0; reg data_in = 0; wire data_out; fsm_1 dut ( .clk (clk ), .rstn (rstn ), .data_in (data_in ), .data_out ( data_out) ); initial begin #50 rstn = 1; data_in = 0; #20 data_in = 1; #20 data_in = 0; #20 data_in = 1; #20 data_in = 0; #20 data_in = 1; #20 data_in = 1; #20 data_in = 0; #20 data_in = 1; end always #10 clk = ! clk ; endmodule
`timescale 1ns/1ps module fsm_2 ( input clk, //50MHZ input rstn, //复位信号 input data_in, output reg data_out ); //序列检测101--可重叠Moore型--需要四个状态 parameter S0 = 4'b0001, S1 = 4'b0010, S2 = 4'b0100, S3 = 4'b1000; reg [3:0] c_state; reg [3:0] n_state; //fsm 二段式写法 写法相对容易维护,不过组合逻辑输出容易出现毛刺等问题 //第一个always块:进行当前状态和下一个状态的切换 时序逻辑 always @(posedge clk or negedge rstn) begin if(!rstn) c_state <= S0; else c_state <= n_state; end //第二个always块:实现输入、输出以及状态跳转判断 组合逻辑 阻塞赋值 = always @(*) begin if (!rstn) begin n_state = S0; data_out = 0; end else case(c_state) S0: begin if(data_in == 1)begin n_state = S1; data_out = 0; end else begin n_state = S0; data_out = 0; end end S1: begin if(data_in == 0)begin n_state = S2; data_out = 0; end else begin n_state = S1; data_out = 0; end end S2: begin if(data_in == 1) begin n_state = S3; data_out = 0; end else begin n_state = S0; data_out = 0; end end S3: begin data_out = 1; //Moore型状态机,其输出只和S3状态有关 if (data_in == 1) begin n_state = S1; end else begin n_state = S2; end end default : begin n_state = S0; end endcase end endmodule
`timescale 1ns / 1ps module fsm_2_tb; // Parameters localparam S0 = 4'b0001; // Ports reg clk = 0; reg rstn = 0; reg data_in = 0; wire data_out; fsm_2 uut ( .clk (clk ), .rstn (rstn ), .data_in (data_in ), .data_out ( data_out) ); initial begin begin #50 rstn = 1; data_in = 0; #20 data_in = 1; #20 data_in = 0; #20 data_in = 1; #20 data_in = 0; #20 data_in = 1; #20 data_in = 1; #20 data_in = 0; #20 data_in = 1; end end always #10 clk = ! clk ; endmodule
`timescale 1ns/1ps module fsm_3 ( input clk, //50MHZ input rstn, //复位信号 input data_in, output reg data_out ); //序列检测101--可重叠Moore型--需要四个状态 parameter S0 = 4'b0001, S1 = 4'b0010, S2 = 4'b0100, S3 = 4'b1000; reg [3:0] c_state; reg [3:0] n_state; //fsm 三段式写法 //代码易维护,时序逻辑的输出解决了二段式写法中组合逻辑的毛刺问题, //但是三段式消耗的资源相对多一点 //第一个always块:进行当前状态和下一个状态的切换 时序逻辑 always @(posedge clk or negedge rstn) begin if(!rstn) c_state <= S0; else c_state <= n_state; end //第二个always块:实现输入以及状态跳转判断 组合逻辑 阻塞赋值 = always @(*) begin if (!rstn) begin n_state = S0; end else case(c_state) S0: begin if(data_in == 1)begin n_state = S1; end else begin n_state = S0; end end S1: begin if(data_in == 0)begin n_state = S2; end else begin n_state = S1; end end S2: begin if(data_in == 1) begin n_state = S3; end else begin n_state = S0; end end S3: begin if (data_in == 1) begin n_state = S1; end else begin n_state = S2; end end default : begin n_state = S0; end endcase end //第三个always块:实现输出 时序逻辑 非阻塞赋值 <= always @(posedge clk or negedge rstn) begin if (!rstn) data_out <= 1'b0; else if (n_state == S3) data_out <= 1'b1; else data_out <= 1'b0; end endmodule
`timescale 1ns/1ps module fsm_3_tb; // Parameters localparam S0 = 4'b0001; // Ports reg clk = 0; reg rstn = 0; reg data_in = 0; wire data_out; fsm_3 uut ( .clk (clk ), .rstn (rstn ), .data_in (data_in ), .data_out ( data_out) ); initial begin begin #50 rstn = 1; data_in = 0; #20 data_in = 1; #20 data_in = 0; #20 data_in = 1; #20 data_in = 0; #20 data_in = 1; #20 data_in = 1; #20 data_in = 0; #20 data_in = 1; end end always #10 clk = ! clk ; endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。