HBLbits_Verilog Basic_Fsm serialdp
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 top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
// Modify FSM and datapath from Fsm_serialdata
parameter ID = 0, D1 = 1, D2 = 2, D3 = 3, D4 = 4, D5 = 5, D6 = 6;
parameter D7 = 7, D8 = 8, DP = 9, STOP = 10, DONE = 11, FAL = 12, WAIT = 13;
reg[3:0] state , next;
wire p_s, odd;
always @(*) begin
case(state)
ID: next = (~in) ? D1 : ID;
D1: next = D2;
D2: next = D3;
D3: next = D4;
D4: next = D5;
D5: next = D6;
D6: next = D7;
D7: next = D8;
D8: next = DP;
DP: next = STOP;
STOP: begin
if(in & odd)
next = DONE;
else if (in & ~odd)
next = FAL;
else
next = WAIT;
end
DONE: next = in ? ID : D1;
WAIT: next = in ? ID : WAIT;
FAL: next = in ? ID : D1;
endcase
end
always @ (posedge clk) begin
if(reset)begin
state <= ID; end
else
state <= next;
end
// New: Add parity checking.
assign p_s = ((state == D1) | (state == D2) | (state == D3) | (state == D4) | (state == D5) | (state == D6) | (state == D7) | (state == D8) | (state == DP) );
wire p_in;
assign p_in = p_s & in;
wire p_rst;
assign p_rst = (reset | (state == ID) | (state == DONE));
parity ptest(
.clk(clk),
.reset(p_rst),
.in(p_in),
.odd(odd));
//output done and byte
assign done = (state == DONE);
reg[9:0]d_s;
always @(posedge clk) begin
if(reset)
d_s <= 10'b0;
else begin
d_s[9] <= in;
d_s[8] <= d_s[9];
d_s[7] <= d_s[8];
d_s[6] <= d_s[7];
d_s[5] <= d_s[6];
d_s[4] <= d_s[5];
d_s[3] <= d_s[4];
d_s[2] <= d_s[3];
d_s[1] <= d_s[2];
d_s[0] <= d_s[1];
end
end
assign out_byte = done ? d_s[7:0] : 8'b0;
endmodule
//另一方法
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
parameter IDLE = 3'd0,DATA = 3'd1,REC_PAR = 3'd2,DECTION = 3'd3,STOP= 3'd4,WAIT= 3'd5;
//IDLE空閒狀態,只有當in拉低時,跳轉到接收資料狀態
//DATA接收資料狀態,重複8次,當counter為7時,跳轉到接收同位狀態
//REC_PAR接收同位狀態
//DECTION 檢測in是否拉高,同時奇偶檢驗,只有同時滿足跳轉到stop狀態,這個狀態和空閒狀態是一樣的可以合併
//WAIT等候狀態,檢測in是否拉高,拉高跳轉到空閒狀態
reg [2:0] state,next_state;
reg done_reg;
reg [7:0] data;//保存8bit資料
reg [2:0] counter;//計數器
//連接同位模組信號
wire par_enable;//這個信號是給同位模組reset埠的
wire odd;
always@(posedge clk)begin
if(reset)begin
state <= IDLE;
end
else begin
state <= next_state;
end
end
always@(*)begin
case(state)
IDLE:begin
if(in)begin
next_state <= IDLE;
end
else begin
next_state <= DATA;
end
end
DATA:begin
if(counter == 3'd7)begin
next_state <= REC_PAR;
end
else begin
next_state <= DATA;
end
end
REC_PAR:next_state <= DECTION;
DECTION:begin
if(in)begin
next_state <= STOP;
end
else begin
next_state <= WAIT;
end
end
STOP:begin
if(in)begin
next_state <= IDLE;
end
else begin
next_state <= DATA;
end
end
WAIT:begin
if(in)begin
next_state <= IDLE;
end
else begin
next_state <= WAIT;
end
end
default:next_state <= IDLE;
endcase
end
always@(posedge clk)begin
if(reset)begin
done_reg <= 0;
par_enable <= 1;//這個信號是給同位模組reset埠的
data <= 0;//保存8bit資料
counter <= 0;
end
else begin
case(state)
IDLE:begin
if(in)begin
par_enable = 1;
end
else begin
par_enable = 0;
end
end
DATA:begin
counter <= counter + 1;
data[counter] <= in;
end
REC_PAR:begin
counter <= 0;
par_enable = 1;//這一條是最關鍵的一條,只有當下一個週期par_enable信號拉高才正確
end
DECTION:begin
if(in)begin
done_reg <= odd;
end
else begin
done_reg <= 0;
end
end
STOP:begin
done_reg <= 0;
if(in)begin
par_enable = 1;
end
else begin
par_enable = 0;
end
end
WAIT:begin
done_reg <= 0;
if(in)begin
par_enable = 1;
end
else begin
par_enable = 1;
end
end
default:begin
done_reg <= 0;
par_enable <= 1;//這個信號是給同位模組reset埠的
data <= 0;//保存8bit資料
counter <= 0;
end
endcase
end
end
assign done = done_reg;
assign out_byte = done ? data : 0;
parity p1(
.clk(clk),
.reset(par_enable),
.in(in),
.odd(odd));
endmodule
沒有留言:
張貼留言