1、最近看别人有面试说遇到这样一个问题。用状态机实现类似序列检测的题目:生成01011011101111…依次类推。针对这个问题,我设计如下的三段式状态机代码,用了4个状态,2个计数器。
设计之初,本来是没有START这个状态的,在第三段时候,用c_state作为判断量。但是会出现011011101111…这样的情况,而且done信号是不符合自己设计之初的思路。所以改成用n_state去做判断量,但是又会由于IDLE不会进入,导致出错,所以加了一个START,即赋初值的状态。
module data(
input clk,
input rst_n,
output reg data
);
parameter IDLE = 2'b00;
parameter S1 = 2'b01;
parameter S2 = 2'b10;
parameter START = 2'b11;
reg [1:0] c_state;
reg [1:0] n_state;
reg [5:0] cnt; //作为本次1的个数的计数器,递减
reg [5:0] cnt_temp; //计算下一次循环时候1的个数
reg done;
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
c_state <= IDLE;
end
else begin
c_state <= n_state;
end
end
always @ (*) begin
case(c_state)
IDLE : begin
n_state = START;
end
START : begin
n_state = S1;
end
S1 : begin
n_state = S2;
end
S2 : begin
if(done) begin
n_state = S1;
end
else begin
n_state = S2;
end
end
default : begin
end
endcase
end
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
data <= 1'b0;
cnt <= 6'd0;
end
else begin
case(n_state)
START : begin
cnt <= 6'd0;
data <= 1'b0;
cnt_temp <= 6'd1;
end
S1 : begin
cnt <= cnt_temp;
cnt_temp <= cnt_temp + 1'b1;
data <= 1'b0;
done <= 1'b0;
end
S2 : begin
cnt <= cnt - 1'b1;
data <= 1'b1;
if(cnt==6'b1) begin
done <= 1'b1;
end
else begin
done <= 1'b0;
end
end
default : begin
end
endcase
end
end
endmodule
测试代码:
`timescale 1ps/1ps
module tb();
reg clk;
reg rst_n;
wire data;
data inst(
.rst_n(rst_n),
.clk(clk),
.data(data)
);
initial begin
clk = 0;
rst_n = 0;
#22;
rst_n = 1;
end
always #5 clk = ~clk;
endmodule
仿真代码如下:
总共用了18个寄存器。
如果有什么别的思路或者更好的设计方法麻烦留言。