用Verilog 实现一个帧结构的串行数据接收器;
串行数据输入为:NRZ数据加位时钟(BCL)格式,高位在前 帧结构为:8位构成一个字,64字构成一个帧。每帧的第一个字为同步字。 同步字图案存储在可由CPU读写的同步字寄存器(端口地址00H)中 串行接受器在连续检测到3个同步图案后,开始接受数据,并向CPU中传送数据。串行数据接收器每接收到一个字,先送到数据寄存器中, CPU以I/O读方式,从数据寄存器中读取数据(端口地址为01H) 若数据寄存器已满,再有数据写入时,则覆盖原有的数据。在数据寄存器为空时,CPU从数据寄存器中读到的数据将是同步字寄存器的内容。 在接收数据过程中,若任何一帧的同步字不匹配,则进入到头步状态,停止数据接收。失步后,必须重新同步(连续检测到3个同步图案),然后开始新的数据接收。 寄存器的读写采用和8031类似的控制方式,有关信号包括:双向数据(DATA[7:0])、I/O地址(ADDR[7:0])、I/O写(IOW)、和I/O读(IOR),其中IOW和IOR都是低电平有效 设计者可以根据需要增加其它的输入输出信号
设计分析
端口 输入数据和时钟之间的关系 帧结构 8位构成一个字,64字构成一个帧。每帧的第一个字为同步字。 连续检测到三个同步帧 ,即连续三个同步头和同步图案一样的帧,才开始进行数据接收 详细设计-工作阶段非常明显 失步阶段:检测同步头,根据情况确定是否转入同步状态 同步阶段:检测同步头,如果匹配则接收数据,仍然处于同步阶段;否则转入失步状态。 注意:是台下检测i的一个同步字时需要每个时钟周期都要进行比较 实现思路:采用状态机进行实现 状态转换的控制 计数器:接收位计数–>字,字计数–>数据帧 比较器:枕头数据与同步字的比较 两个状态 该状态转换关系从功能需求很容易得出 难点:需要检测三个连续的同步帧才能从失步态到同步态 控制不清晰 四状态划分 实现难点:每个帧持续8*64个时钟周期,其中第8个时钟周期结束需要同步头比较,后面的504个时钟周期接收数据(同步态)或空等(失步态) 8个状态 在每个状态,省略了自身状态转移的情况 每个R_Headx状态持续八个周期(Read_Head1)除外 每个R_Datax状态持续504个周期 需要设计一个记8和一个记64的计数器辅助进行控制 代码部分 完整代码
module S2P ( reset, clk, serial_in, ior, iow, address, data
) ; input reset; input clk; input serial_in; input ior; input iow; input [ 7 : 0 ] address; input [ 7 : 0 ] data; reg [ 7 : 0 ] Data; reg counter8_en, counter504_en, counter8_clr, counter504_clr; reg [ 2 : 0 ] counter8; reg [ 8 : 0 ] counter504; reg [ 7 : 0 ] shifter, data_reg, sync_word; reg [ 2 : 0 ] pres_state, next_state; parameter R_Head1 = 3 'b000, R_Data1 = 3 'b001, R_Head2 = 3 'b010, R_Data2 = 3 'b011, R_Head3 = 3 'b100, R_Data3 = 3 'b101, R_Head = 3 'b110, R_Data = 3 'b111; always @( posedge reset or posedge clk) beginif ( reset) pres_state = R_Head1; else pres_state = next_state; endalways @( pres_state, shifter, counter8, counter504) begincase ( pres_state) R_Head1: if ( shifter == sync_word) next_state = R_Data1; else next_state = R_Head1; R_Data1: if ( counter504 == 9 'b0) next_state = R_Head2; else next_state = R_Data1; R_Head2: if ( counter8 == 3 'b0) beginif ( shifter == sync_word) next_state = R_Data2; else next_state = R_Head1; end else next_state = R_Head2; R_Data2: if ( counter504 == 9 'b0) next_state = R_Head3; else next_state = R_Data2; R_Head3: if ( counter8 == 3 'b0) beginif ( shifter == sync_word) next_state = R_Data3; else next_state = R_Head1; end else next_state = R_Head3; R_Data3: if ( counter504 == 9 'b0) next_state = R_Head; else next_state = R_Data3; R_Head: if ( counter8 == 3 'b0) beginif ( shifter == sync_word) next_state = R_Data; else next_state = R_Head1; end else next_state = R_Head; R_Data: if ( counter504 == 9 'b0) next_state = R_Head; else next_state = R_Data; default : next_state = pres_state; endcaseendalways @( posedge reset or posedge clk) beginif ( reset) shifter = 8 'b0; else shifter = { serial_in, shifter[ 7 : 1 ] } ; endalways @( posedge clk or posedge reset) beginif ( reset) counter8 = 3 'b111; else beginif ( counter8_clr) counter8 = 3 'b111; else if ( counter8_en) counter8 = counter8 - 1 ; endendalways @( posedge clk or posedge reset) beginif ( reset) counter504 = 3 'b111; else beginif ( counter504_clr) counter504= 3 'b111; else if ( counter504_en) counter504 = counter504 - 1 ; endendalways @( pres_state) beginif ( pres_state == R_Data1 || pres_state == R_Data2 || pres_state == R_Data3 || pres_state == R_Data) counter8_clr = 1 'b1; else counter8_clr = 1 'b0; endalways @( pres_state) beginif ( pres_state == R_Head2 || pres_state == R_Head3 || pres_state == R_Head) counter8_en = 1 'b1; else counter8_en = 1 'b0; endalways @( pres_state) beginif ( pres_state == R_Head1 || pres_state == R_Head2 || pres_state == R_Head3 || pres_state == R_Head) counter504_clr = 1 'b1; else counter504_clr = 1 'b0; endalways @( pres_state) beginif ( pres_state == R_Data1 || pres_state == R_Data2 || pres_state == R_Data3 || pres_state == R_Data) counter504_en = 1 'b1; else counter504_en = 1 'b0; endalways @( posedge reset or posedge clk) if ( reset) data_reg = 8 'b0; else if ( counter504_en == 1 'b1 && counter504[ 2 : 0 ] == 3 'b0) data_reg = shifter; always @( posedge reset or posedge clk) beginif ( reset) sync_word = 8 'b0; else if ( iow == 1 'b0 && address == 8 'b0) sync_word = data; endalways @( ior or address or data_reg) if ( ior == 1 'b0&& address == 8 'b1) Data = data_reg; else Data = 8 'bz; assign data = Data;
endmodule