Serial receiver with parity checking
See also: Serial receiver and datapath
We want to add parity checking to the serial receiver. Parity checking adds one extra bit after each data byte. We will use odd parity, where the number of 1s in the 9 bits received must be odd. For example, 101001011 satisfies odd parity (there are 5 1s), but 001001011 does not.
Change your FSM and datapath to perform odd parity checking. Assert the done signal only if a byte is correctly received and its parity check passes. Like the serial receiver FSM, this FSM needs to identify the start bit, wait for all 9 (data and parity) bits, then verify that the stop bit was correct. If the stop bit does not appear when expected, the FSM must wait until it finds a stop bit before attempting to receive the next byte.
You are provided with the following module that can be used to calculate the parity of the input stream (It's a TFF with reset). The intended use is that it should be given the input bit stream, and reset at appropriate times so it counts the number of 1 bits in each byte.
module parity (
input clk,
input reset,
input in,
output reg odd);
always @(posedge clk)
if (reset) odd <= 0;
else if (in) odd <= ~odd;
endmodule
另请参阅:串行接收器和数据路径
我们想向串行接收器添加奇偶校验。奇偶校验在每个数据字节后增加一个额外的位。我们将使用奇偶校验,其中接收的 9 位中的 1秒数必须为奇数。例如,101001011满足奇奇偶校验(有 5 个 1秒),但001001011不满足。
更改 FSM 和数据路径以执行奇偶校验。仅当正确接收到字节且其奇偶校验通过时,才断言已完成的信号。像串行接收机 FSM,此 FSM 需要识别起始位,等待所有 9 位(数据和奇偶校验)位,然后验证停止位是否正确。如果停止位未按预期出现,则 FSM 必须等到找到停止位后再尝试接收下一个字节。
您将获得以下模块,该模块可用于计算输入流的奇偶校验(它是具有重置功能的 TFF)。预期用途是应为其提供输入位流,并在适当的时候复位,以便计算每个字节中的 1 位数。
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
parameter IDLE = 3'd0,START = 3'd1,DATA = 3'd2;
parameter STOP = 3'd3,WAIT = 3'd4;
reg [2:0] current_state,next_state;
reg [3:0] counter;
reg [8:0] data_in;
reg odd_temp;
wire Isdone;
// Modify FSM and datapath from Fsm_serialdata
always @(*) begin
case(current_state)
IDLE:begin
if(~in)begin
next_state = START;
end
else begin
next_state = IDLE;
end
end
START:begin
next_state = DATA;
end
DATA:begin
if(counter == 4'd9)begin
next_state = in ? STOP : WAIT;
end
else begin
next_state = DATA;
end
end
STOP:begin
next_state = in ? IDLE : START;
end
WAIT:begin
next_state = in ? IDLE : WAIT;
end
default:begin
next_state = IDLE;
end
endcase
end
always @(posedge clk) begin
if(reset)begin
current_state <= IDLE;
end
else begin
current_state <= next_state;
end
end
always @(posedge clk) begin
if(reset)begin
done <= 1'd0;
out_byte <= 8'd0;
counter <= 4'd0;
end
else begin
case(next_state)
IDLE:begin
done <= 1'd0;
out_byte <= 8'd0;
counter <= 4'd0;
end
START:begin
done <= 1'd0;
out_byte <= 8'd0;
counter <= 4'd0;
end
DATA:begin
done <= 1'd0;
out_byte <= 8'd0;
counter <= counter + 1'd1;
data_in[counter] <= in;
end
STOP:begin
done <= odd_temp ? 1'd1 : 1'd0;
out_byte <= odd_temp ? data_in[7:0] : 8'd0;
counter <= 4'd0;
end
WAIT:begin
done <= 1'd0;
out_byte <= 8'd0;
counter <= 4'd0;
end
endcase
end
end
// New: Add parity checking.
assign Isdone = (next_state == START);
parity u0(clk,Isdone,in,odd_temp);
endmodule