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
Note that the serial protocol sends the least significant bit first, and the parity bit after the 8 data bits.
Some timing diagrams
No framing errors. Odd parity passes for first byte, fails for second byte.
Module Declaration
module top_module( input clk, input in, input reset, // Synchronous reset output [7:0] out_byte, output done );
这道题需要注意的点是,当接收完 8 bits 数据后,还需要接收 1 bit 的校验位。这个校验位需要先经过校验模块处理(经历一个时钟周期),然后再被主模块采样。因此,主模块对校验位和停止位的采样发生在同一个时钟周期。
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
parameter IDLE = 6'b0000_01;
parameter SAMPLE_START = 6'b0000_10;
parameter BITSTREAM = 6'b0001_00;
parameter WAIT = 6'b0010_00;
parameter SAMPLE_PARITY_STOP = 6'b0100_00;
parameter ERROR = 6'b1000_00;
reg [5:0] cur_state, nxt_state;
reg [3:0] bits_cnt;
reg [7:0] out_byte_q;
wire odd;
reg parity_reset;
parity u_parity(
clk,
parity_reset,
in,
odd
);
//fms
always @(*)
begin
case (cur_state)
IDLE:
begin
nxt_state = in?IDLE:SAMPLE_START;
end
SAMPLE_START:
begin
nxt_state = BITSTREAM;
end
BITSTREAM:
begin
nxt_state = (bits_cnt == 4'h8)?WAIT:BITSTREAM;
end
WAIT:
begin
case({odd,in})
2'b00:
nxt_state = ERROR;
2'b01:
nxt_state = IDLE;
2'b10:
nxt_state = ERROR;
2'b11:
nxt_state = SAMPLE_PARITY_STOP;
default:
nxt_state = IDLE;
endcase
end
SAMPLE_PARITY_STOP:
begin
nxt_state = in?IDLE:SAMPLE_START;
end
ERROR:
begin
nxt_state = in?IDLE:ERROR;
end
default:
begin
nxt_state = IDLE;
end
endcase
end
always @(posedge clk)
begin
if(reset)
cur_state <= IDLE;
else
cur_state<= nxt_state;
end
//
//bits_cnt
always @(posedge clk)
begin
if(reset)
bits_cnt <= 4'h0;
else if(bits_cnt == 4'h8)
bits_cnt <= 4'h0;
else if(cur_state == SAMPLE_START || cur_state == BITSTREAM)
bits_cnt <= bits_cnt + 1'h1;
else
bits_cnt <= 4'h0;
end
always @(posedge clk)
begin
if(reset)
out_byte_q <= 8'h0;
else if(cur_state == SAMPLE_PARITY_STOP)
out_byte_q <= 8'h0;
else if(cur_state == SAMPLE_START || (cur_state == BITSTREAM && bits_cnt < 8'h8))
out_byte_q <= {in,out_byte_q[7:1]};
else
out_byte_q <= out_byte_q;
end
always @(posedge clk)
begin
if(reset)
parity_reset <= 1'h1;
else
begin
case(cur_state)
IDLE:
begin
parity_reset = in?1'h1:1'h0;
end
SAMPLE_START:
begin
parity_reset = 1'h0;
end
BITSTREAM:
begin
parity_reset = 1'h0;
end
WAIT:
begin
parity_reset = 1'h1;
end
SAMPLE_PARITY_STOP:
begin
parity_reset = 1'h1;
end
ERROR:
begin
parity_reset = 1'h1;
end
default:
begin
parity_reset = 1'h1;
end
endcase
end
end
assign done = cur_state == SAMPLE_PARITY_STOP;
assign out_byte = out_byte_q;
// Modify FSM and datapath from Fsm_serialdata
// New: Add parity checking.
endmodule