Written in the front, yesterday a netizen asked me about the state machine, so as to make a record: design a sequence detector record that can be detected cyclically.
Virtual machine: VMware -14.0.0.24051
Environment: ubuntu 18.04.1 Script
: makefile ( click to go )
Utility: vcs and verdi
Article directory
1. Demand
The function of the module is to detect the occurrence of a 5-digit binary 10010 in the serial data stream, and realize cyclic detection (after detecting 10010, if the subsequent data input is 010), that is, the sequence is 10010010xxx, and the sequence needs to be detected twice. , build a test platform for functional verification.
2. Spec
(1)Analyze
According to the requirements, the width of the sequence to be detected is 5, then including the IDLE state, the state machine has a total of 6 states, which can be set as IDLE, S1, S2, S3, S4, S5. One-hot encoding is used. Each time a sequence is detected, a signal is output, and the counter is incremented by 1 to record how many times it has been detected.
In the low-speed system, the number of states in the state machine is less than 4, using binary code encoding
In the low-speed system, the number of states in the state machine is 4~24, using one-hot code encoding
In the low-speed system, the state machine The number of states in the middle is > 24, using Gray code encoding
(2)Interface Description
Signal Name | Width | Direction | Description |
---|---|---|---|
clk | 1 | input | System clk signal, xxMhz |
rst | 1 | input | System reset signal |
data | 1 | input | Detected data |
result | 1 | output | Detection result signal |
res_cnt | 2 | output | The number of occurrences of the sequence |
(3)FSM
三、Design and Functional Verification
(1)RTL
//-- modified by xlinxdu, 2022/04/24
module check #(
parameter WIDHT = 2
)(
input clk_i ,
input rst_n_i ,
//-- interface
input data_i ,
output reg result_o ,
output reg [WIDHT-1:0] res_cnt_o //(sum)
);
//-- state define
parameter IDLE = 6'b00_0001;
parameter S1 = 6'b00_0010;
parameter S2 = 6'b00_0100;
parameter S3 = 6'b00_1000;
parameter S4 = 6'b01_0000;
parameter S5 = 6'b10_0010;
reg [5:0] cur_state;//current state
reg [5:0] nxt_state;//next state
wire result_s ;//sum
reg nres_cnt ;//
/*-----------------------------------------------\
----------- updata of current state ----------
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
cur_state <= 6'b0;
end
else begin
cur_state <= nxt_state;
end
end
/*-----------------------------------------------\
-------------- transfer of state -------------
\-----------------------------------------------*/
always @ (*) begin
case(cur_state)
IDLE: if(data_i) nxt_state = S1 ;
else nxt_state = IDLE;
S1 : if(data_i) nxt_state = S1 ;
else nxt_state = S2 ;
S2 : if(data_i) nxt_state = S1 ;
else nxt_state = S3 ;
S3 : if(data_i) nxt_state = S4 ;
else nxt_state = IDLE;
S4 : if(data_i) nxt_state = S1 ;
else nxt_state = S5 ;
S5 : if(data_i) nxt_state = S1 ;
else nxt_state = S3 ;
default: nxt_state = IDLE;
endcase
end
/*-----------------------------------------------\
--------- updata of result counter -----------
\-----------------------------------------------*/
always @ (*) begin
if(nxt_state == S5) begin
nres_cnt = 1'b1;
end
else begin
nres_cnt = 1'b0;//clear
end
end
always @ (posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
res_cnt_o <= 2'b0;
end
else begin
res_cnt_o <= res_cnt_o + nres_cnt;
end
end
/*-----------------------------------------------\
---------- updata of result_o ----------
\-----------------------------------------------*/
//assign result_s = (cur_state == S4) ? 1'b1 : 1'b0;
assign result_s = (nxt_state == S5) ? 1'b1 : 1'b0;
always @ (posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
result_o <= 1'b0;
end
else begin
result_o <= result_s;
end
end
endmodule
(2)Test Bench
module tb_check;
reg clk_i ;
reg rst_n_i ;
reg data_i ;
wire result_o ;
wire [1:0] res_cnt_o;
reg [17:0] data_check;
initial begin
clk_i = 0 ;
rst_n_i = 1;
data_i = 0;
data_check = 18'b10_1001_0001_0010_0100;
#5 rst_n_i = 0;
#10 rst_n_i = 1;
end
always begin
data_i = data_check[17];
#60 data_check = (data_check << 1'b1);
end
check tb_check(
.clk_i (clk_i ),
.rst_n_i (rst_n_i ),
.data_i (data_i ),
.result_o (result_o ),
.res_cnt_o(res_cnt_o)
);
always begin
#30 clk_i = ~clk_i;
end
initial begin
#2000 $finish;
$fsdbDumpfile("check.fsdb");
$fsdbDumpvars ;
$fsdbDumpMDA ;
end
endmodule
4. Result
In the test platform, the input data is data_check = 18'b10_1001_0001_0010_0100, which is converted into a serial data stream and input to the DUT under test. See the three boxes in the figure above, and 10010 appears three times. The function realizes that one signal is output at each detection, and the number is recorded once, which ensures the basic data path of the module.
Author: xlinxdu
Copyright: This article is the original author, and the copyright belongs to the author.
Reprinting: Reprinting is prohibited without the permission of the author. Reprinting must retain this statement, and a link to the original text must be given in the article.