FSM Design T3
设计一个电路,其可以接收串行比特流(假设信息流的注入模式是0111B,数据流的最低有效位(二进制数的最右边位)首先到达状态机),并产生串行输出。考虑如下情形:(1)当识别出输入序列为0111时,输出在一个时钟周期内为高电平;(2)在再次检测出0111之前,输出将维持低电平;(3)在第二次检测到0111出现时,输出将再次为一个时钟周期的高电平,如此继续。(4)当它检测到6个0111序列之后就停止检测,直到复位信号有效后重新检测。用Verilog完成设计。(输入信号至少包含reset和clock)注:输入信号名为IN,输出信号名为OUT,testbench编写时应包括(4)中检测到6个序列之后就停止检测的情况。
1. Analysis
根据题意可知需要实现一个数据检测器,当电路接收指定的数据流(0111)时产生高电平输出,否则电路一直保持低电平输出状态。因此,电路的输出不仅与当前状态有关也和输入信号有关,本文可以利用Mealy型的FSM来实现以上要求,通过预先设置四个状态S0、S1、S2、S3,每接收1位二进制信号就计算并实现状态跳转。对于题目中要求检测6次0111序列后停止检测,本文可以设置一个寄存器类型的计数变量cnt,每实现一次0111检测就自动加一,只有当该计数变量cnt小于6时才有高电平输出。
2. FSM Diagram
3. Port List
Port Name | Attribute | Width | Meaning |
---|---|---|---|
clock | input | 1 bit | 时钟信号 |
reset | input | 1 bit | 复位信号 |
in | input | 1 bit | 状态机输入信号IN |
out | output | 1 bit | 状态机输出信号OUT |
4. Verilog Code
`timescale 1ns/1ps
module exercise3 (CLK, RST, IN, OUT);
input wire CLK;
input wire RST;
input wire IN;
output reg OUT;
reg [3:0] cs;
reg [3:0] ns;
reg [5:0] cnt;
parameter s0 = 4'b0001;
parameter s1 = 4'b0010;
parameter s2 = 4'b0100;
parameter s3 = 4'b1000;
always @ (posedge CLK or negedge RST) begin
if (!RST) begin
cs <= s0;
cnt <= 6'd0;
end
else if ((cs == s2) && (ns == s3)) begin
cs <= ns;
cnt <= cnt + 6'd1;
end
else begin
cs <= ns;
end
end
always @ (*) begin
case (cs)
s0: begin
if (IN == 1'b1) begin
ns = s1;
end
else begin
ns = s0;
end
end
s1: begin
if (IN == 1'b1) begin
ns = s2;
end
else begin
ns = s0;
end
end
s2: begin
if (IN == 1'b1) begin
ns = s3;
end
else begin
ns = s0;
end
end
s3: begin
if (IN == 1'b1) begin
ns = s3;
end
else begin
ns = s0;
end
end
default: ns = s0;
endcase
end
always @ (posedge CLK or negedge RST) begin
case (ns)
s3: begin
if ((cs == s2) && (cnt < 6'd6)) begin
OUT <= 1'b1;
end
else begin
OUT <= 1'b0;
end
end
default: OUT <= 1'b0;
endcase
end
endmodule
5. Testbench Code
`timescale 1ns/1ps
module exercise3_test;
reg CLK;
reg RST;
reg IN;
wire OUT;
parameter half_cycle = 5;
parameter s0 = 4'b0001;
parameter s1 = 4'b0010;
parameter s2 = 4'b0100;
parameter s3 = 4'b1000;
exercise3 exercise3_inst (
.CLK(CLK),
.RST(RST),
.IN(IN),
.OUT(OUT)
);
initial begin
CLK = 0;
forever begin
CLK = # half_cycle ~ CLK;
end
end
initial begin
RST = 1;
# (1 * half_cycle) RST = 0;
# (2 * half_cycle) RST = 1;
end
initial begin
IN = 0;
# (6 * half_cycle) IN = 0;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 0;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 0;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 0;
# (2 * half_cycle) IN = 0;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 0;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 0;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 0;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 0;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 1;
# (2 * half_cycle) IN = 0;
end
initial begin
# (100 * half_cycle) $finish;
end
initial begin
$fsdbDumpfile("./verdiFsdb/exercise3.fsdb");
$fsdbDumpvars(0);
end
endmodule