HDLbits—Fsm ps2data
这道题目相比上一道多了数据位输出,当done信号为1时,输出24bit的数据,这24bit的数据高8位,中8位,低8位分别从in[3]为1开始计起,依次输出。done信号为0的时候不关心数据信号。out_bytes这个信号感觉只有用assign才能周期匹配,而done可以使用assign或者在s2状态就赋值1。
主要是熟悉三段式状态机的写法。
关于三段式状态机的一点总结
- 确定输入输出信号,及其类型(是wire还是reg);
- 声明内部信号,一般需要定义current_state和next_state;
- 用3个always语句描述状态机;第一个用来次态和现态的转换,第二个always用于现态在输入情况下转换为次态的组合逻辑;第三个语句用于现态到输出的组合逻辑输出。
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output [23:0] out_bytes,
output done); //
parameter S0 = 2'd0,S1 = 2'd1,S2 = 2'd2,S3 = 2'd3; //状态数S0 起始状态第1个数据进入,S1第2个数据进入
//S2第3个数据进入,S3 done状态,输出out_bytes
reg [23:0] temp; //暂存数据
reg [1:0] state,next_state;
状态寄存器
always@(posedge clk or posedge reset)begin
if(reset )begin
state = S0;
end//reset
else begin
state = next_state;
end//else
end//always
//次态的组合逻辑
always@(*)begin
case(state)
S0:begin
if(in[3])begin
next_state = S1;
end//in[3]
else begin
next_state = S0;
end//else
end//s0
S1:next_state = S2;
S2:next_state = S3;
S3:begin
if(in[3])begin
next_state = S1;
end//in[3]
else begin
next_state = S0;
end//else
end//s3
default:next_state = S0;
endcase
end//always
//输出逻辑
always@(posedge clk or posedge reset)begin
if(reset)begin
temp <= 0;
end
else begin
case(state)
S0:begin
if(in[3])begin
temp[23:16] = in;
end//in[3]
else begin
temp = 0;
end//else
end//s0
S1:begin
temp[15:8] <= in;
end
S2: begin
temp[7:0] <= in;
done <= 1;//由于是时序电路,要使done在s3高电平,所以在前一个周期拉高,同时也可以使用assign
end
S3:begin
done <= 0;
if(in[3])begin
temp[23:16] = in;
end//in[3]
else begin
temp = 0;
end//else
end//s0
default:begin
temp <= 0;
end
endcase
end
end
//assign done = (state == S3);
assign out_bytes = done ? temp : 23'd0;
endmodule