前一道题(135.Serial receiver),不用记录数据,只输出接收完成标志done,只要把136中数据存储输出部分删除即可,因此这里不再赘述。
原题链接:https://hdlbits.01xz.net/wiki/Fsm_serialdata
题目简单说明:接收数据格式为:1bit起始位(0)+8bit数据位+1bit停止位(1);若停止位为0则数据传输出错。
状态转换如下图:
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
reg [3:0] state_c, state_n;
parameter Idle=0, Recv=1, Done=2, Error=3, Stop=4;
wire Idle2Recv, Recv2Stop, Stop2Error, Stop2Done, Done2Recv, Done2Idle, Error2Idle;
wire cnt_add, cnt_end;
reg [3:0] cnt;
reg [7:0] temp_data;
always@(posedge clk) begin
if(reset)
cnt <= 0;
else if(cnt_add) begin
if(cnt_end)
cnt <= 0;
else
cnt <= cnt+1;
end
end
assign cnt_add = state_c==Recv;
assign cnt_end = cnt_add && cnt==8-1;
always@(posedge clk) begin
if(reset)
state_c <= Idle;
else
state_c <= state_n;
end
always@(*) begin
case (state_c)
Idle:begin
if(Idle2Recv)
state_n = Recv;
else
state_n = state_c;
end
Recv:begin
if(Recv2Stop)
state_n = Stop;
else
state_n = state_c;
end
Stop:begin
if(Stop2Done)
state_n = Done;
else if(Stop2Error)
state_n = Error;
else
state_n = state_c;
end
Done:begin
if(Done2Recv)
state_n = Recv;
else if(Done2Idle)
state_n = Idle;
else
state_n = state_c;
end
Error:begin
if(Error2Idle)
state_n = Idle;
else
state_n = state_c;
end
default:state_n = Idle;
endcase
end
assign Idle2Recv = state_c==Idle && in==0;
assign Recv2Stop = state_c==Recv && cnt==8-1;
assign Stop2Done = state_c==Stop && in==1;
assign Stop2Error = state_c==Stop && in==0;
assign Done2Recv = state_c==Done && in==0;
assign Done2Idle = state_c==Done && in==1;
assign Error2Idle = state_c==Error && in==1;
assign done = state_c==Done;
always@(posedge clk) begin
if(reset)
temp_data<=8'h00;
else if(state_c == Recv)
temp_data[cnt] = in;
end
assign out_byte = (state_c==Done)?temp_data:8'hzz;
endmodule
数据接收部分使用一个计数器,在接收状态时(state_c=Recv)对cnt计数。
原题链接:https://hdlbits.01xz.net/wiki/Fsm_serialdp
题目简单说明:较上一题多了奇校验部分;接收完数据位和奇校验位后会等待接收停止位,若没有接收到停止位,状态机在接收下一数据时会一直等待接收停止位;奇校验使用题目中提供的模块parity :
module parity (
input clk,
input reset,
input in,
output reg odd);
注意:parity模块的复位信号是组合的;输入信号in只用在Recv接收数据状态下有效;Wait状态是必需的。
状态转换如下图:
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
reg [3:0] state_c, state_n;
parameter Idle=0, Recv=1, Done=2, Error=3, Stop=4, Wait=5;
wire Idle2Recv, Recv2Stop, Stop2Error, Stop2Done, Done2Recv, Done2Idle, Error2Idle;
wire Error2Recv, Stop2Wait, Wait2Idle;
wire cnt_add, cnt_end;
reg [3:0] cnt;
reg [8:0] temp_data;
always@(posedge clk) begin
if(reset)
cnt <= 0;
else if(cnt_add) begin
if(cnt_end)
cnt <= 0;
else
cnt <= cnt+1;
end
end
assign cnt_add = state_c==Recv;
assign cnt_end = cnt_add && cnt==9-1;
always@(posedge clk) begin
if(reset)
state_c <= Idle;
else
state_c <= state_n;
end
always@(*) begin
case (state_c)
Idle:begin
if(Idle2Recv)
state_n = Recv;
else
state_n = state_c;
end
Recv:begin
if(Recv2Stop)
state_n = Stop;
else
state_n = state_c;
end
Stop:begin
if(Stop2Done)
state_n = Done;
else if(Stop2Error)
state_n = Error;
else if(Stop2Wait)
state_n = Wait;
else
state_n = state_c;
end
Done:begin
if(Done2Recv)
state_n = Recv;
else if(Done2Idle)
state_n = Idle;
else
state_n = state_c;
end
Error:begin
if(Error2Idle)
state_n = Idle;
else if(Error2Recv)
state_n = Recv;
else
state_n = state_c;
end
Wait:begin
if(Wait2Idle)
state_n = Idle;
else
state_n = state_c;
end
default:state_n = Idle;
endcase
end
assign Idle2Recv = state_c==Idle && in==0;
assign Recv2Stop = state_c==Recv && cnt==9-1;
assign Stop2Done = state_c==Stop && in==1 && odd;
assign Stop2Error = state_c==Stop && in==1 && ~odd;
assign Done2Recv = state_c==Done && in==0;
assign Done2Idle = state_c==Done && in==1;
assign Error2Idle = state_c==Error && in==1;
assign Error2Recv = state_c==Error && in==0;
assign Stop2Wait = state_c==Stop && in==0;
assign Wait2Idle = state_c==Wait && in==1;
assign done = state_c==Done;
always@(posedge clk) begin
if(reset)
temp_data<=9'h000;
else if(state_c == Recv)
temp_data[cnt] = in;
end
assign out_byte = (done==1)?temp_data[7:0]:8'hzz;
wire odd, parity_in,parity_reset;
assign parity_in = state_c==Recv && in;
assign parity_reset = state_c==Idle || state_c==Error || state_c==Done || reset;
parity U1(.clk(clk),
.reset(parity_reset),
.in(parity_in),
.odd(odd)
);
endmodule
这里奇校验接收和数据接收部分放在了一个状态,因此接收计数cnt=9-1(接收9位数据)。
状态机采用三段式,输出部分使用了组合电路;为代码直观易于理解规范,转换条件单独使用wire类型列出。