菜鸟总结刷hblbits的心得体会,有错误还请指正!
In many (older) serial communications protocols, each data byte is sent along with a start bit and a stop bit, to help the receiver delimit bytes from the stream of bits. One common scheme is to use one start bit (0), 8 data bits, and 1 stop bit (1). The line is also at logic 1 when nothing is being transmitted (idle).
Design a finite state machine that will identify when bytes have been correctly received when given a stream of bits. It needs to identify the start bit, wait for all 8 data 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.
题目分析:比特流中如出现 0(数据位)1 为一个有效数据,done=1;出现 0(数据位)0...01 为无效数据,done=0。
状态机设计:我注意到有些设计者将DATA状态拆分为8个状态,简单粗暴,也容易分析,但这种拓展性不好,若数据位不只是8位,而是很多位,那么状态数就会变多,需要重新画状态机,代码也很冗长。我只使用了4个状态,分别为IDLE、DATA、STOP、WAIT(一开始我并没有设置WAIT,导致不好写输出逻辑表达式,出现很多次错误)。其中DATA 可以表示多位数据位,只需要增加一个计数器判断何时会从DATA状态向下一个状态转变。
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output done
);
parameter IDLE=4'b0001;
parameter DATA = 4'b0010;
parameter STOP = 4'b0100;
parameter WAIT = 4'b1000;
reg [4:0] state, next_state;
reg [3:0] cnt;
//state transition logic
always @(*) begin
case(state)
IDLE: next_state = in ? IDLE:DATA;
DATA: next_state = (cnt==9) ? (in ? STOP : WAIT) : DATA;
STOP: next_state = in ? IDLE : DATA;
WAIT: next_state = in ? IDLE : WAIT;
default: next_state = IDLE;
endcase
end
// state flip-flops
always @(posedge clk) begin
if(reset)
state <= IDLE;
else
state <= next_state;
end
//Output logic
assign done = (state==STOP);
//counter
always@(posedge clk)begin
if(reset)
cnt<=0;
else if(next_state==DATA) /*next_state跟输入in是同步的,
state相比于输入in则会延迟一个时钟*/
cnt <= cnt + 1'b1;
else
cnt <= 0;
end
endmodule
Now that you have a finite state machine that can identify when bytes are correctly received in a serial bitstream, add a datapath that will output the correctly-received data byte. out_byte needs to be valid when done is 1, and is don't-care otherwise.
Note that the serial protocol sends the least significant bit first.
只需要增加一个8bits的右移移位寄存器,再在done=1时输出寄存器的储存的数据即可。
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output done,
output reg [7:0] out_byte
);
parameter IDLE=4'b0001;
parameter DATA = 4'b0010;
parameter STOP = 4'b0100;
parameter WAIT = 4'b1000;
reg [4:0] state, next_state;
reg [3:0] cnt;
reg [7:0] q;
//state transition logic
always @(*) begin
case(state)
IDLE: next_state = in ? IDLE:DATA;
DATA: next_state = (cnt==9) ? (in ? STOP : WAIT) : DATA;
STOP: next_state = in ? IDLE : DATA;
WAIT: next_state = in ? IDLE : WAIT;
default: next_state = IDLE;
endcase
end
// state flip-flops
always @(posedge clk) begin
if(reset)
state <= IDLE;
else
state <= next_state;
end
//counter
always@(posedge clk)begin
if(reset)
cnt<=0;
else if(next_state==DATA) /*next_state跟输入in是同步的,
state相比于输入in则会延迟一个时钟*/
cnt <= cnt + 1'b1;
else
cnt <= 0;
end
// New: Datapath to latch input bits.
always @(posedge clk) begin //增加一个8bits的register
if(next_state==DATA)
q <= {in,q[7:1]};
end
//Output logic
assign done = (state==STOP);
assign out_byte = done ? q : 8'bx;
endmodule
1、原题目
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.
这道题增加了一位奇偶校验位,判断数据在传输过程中是否出现错误。
状态机不需要更改,这时DATA状态包括data和parity ,增加了1 bit 的parity,共9 bits,因此只需将状态转换逻辑中的cnt==9改为cnt==10即可。
done=1需要同时满足一个字节被正确接收和奇偶校验通过,即state=STOP和odd=0(关于odd=0的原因代码中有注释)。
必须正确设置Parity模块中的复位信号,否则done会输出错误。需要在上一个DATA状态结束之后进入下一个DATA状态前复位,或者top_module中的reset复位信号来到时复位。
由于DATA共有9比特,而只需输出8比特的data,因此在datapath中需要增加cnt<9的判断条件,防止奇偶校验位输出。
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
);
parameter IDLE = 4'b0001;
parameter DATA = 4'b0010;
parameter STOP = 4'b0100;
parameter WAIT = 4'b1000;
reg [4:0] state, next_state;
reg [3:0] cnt;
reg [7:0] q;
reg odd;
//state transition logic
always @(*) begin
case(state)
IDLE: next_state = in ? IDLE : DATA;
DATA: next_state = (cnt==10) ? (in ? STOP : WAIT) : DATA;
STOP: next_state = in ? IDLE : DATA;
WAIT: next_state = in ? IDLE : WAIT;
default: next_state = IDLE;
endcase
end
// state flip-flops
always @(posedge clk) begin
if(reset)
state <= IDLE;
else
state <= next_state;
end
// New: Add parity checking.
reg reset_p;
assign reset_p = (state==STOP) || reset || (state==IDLE);
parity U1 (.clk(clk), .reset(reset_p), .in(in), .odd(odd));
//Output logic
assign done = (state==STOP) && ~odd; //使用~odd是因为把停止位的1也算进去了,因此只有odd=0时,done=1;
assign out_byte = done ? q : 8'bx;
//counter
always@(posedge clk)begin
if(reset)
cnt<=0;
else if(next_state==DATA) //next_state跟输入in是同步的,state相比于输入in则会延迟一个时钟
cnt <= cnt + 1'b1;
else
cnt <= 0;
end
// New: Datapath to latch input bits.
always @(posedge clk) begin //增加一个8bits的register
if(next_state==DATA && cnt<9)
q <= {in,q[7:1]}; /*由于是非阻塞赋值,先计算右边的值再更新左侧表达式的值,因此是cnt<9;
若为cnt<10,则数据位的第一位会被右移移位出去,奇偶校验位占据数据位最高位,导致错误*/
end
endmodule