系统同步
两个IC之间的通信,但是两个IC之间通信的时钟由同一个时钟源发出,要考虑的信号的建立时间与保持时间延迟,时钟上也要考虑到两个时钟的时钟抖动和时钟偏斜。
源同步
两个IC之间的通信,前一个IC不仅给后一个IC数据信号也给后一个IC时钟信号,后一个IC的接受数据就是以接受到的时钟信号为同步进行接受,要调整转发时钟的输出时间,数据线长度一定要和走线长度相匹配。
自同步
两个IC之间通信,数据和时钟信息都在一个信息流中发出,后一个IC要根据接受到的数据流对数据流进行解析,一般用作高速串行传输中,比如serdes aurora类的
自同步的发出端要完成并串转换,将并行数据转换为串行数据流发出,接收端完成串并转换将串行数据流转换为并行数据流发出,并同时在数据流内部完成时钟数据恢复。
并串转换实现:
verilog design example
// 并串转换,使用组合逻辑将高位赋值给串行输出,可以取最高位或者最低位输出,要看移位寄存器;
//高位输出,先高位后低位
assign out = left_shift[7];
//需要8个时钟周期完成一个8位信号的并串转换;
always@(posedge clk or negedge rstn)
begin
if(!rstn)
left_shift <= 8'b0;
else if (en)
left_shift <= data_out;
else
left_shift <= {left_shift[6:0],1'b0};
end
-------------------------------------低位输出-----------------------------------
//低位并串转换采用右移寄存器实现
assign out = right_shift[0];
//需要8个时钟周期完成一个8位信号的并串转换;
always@(posedge clk or negedge rstn)
begin
if(!rstn)
right_shift <= 8'b0;
else if (en)
right_shift <= data_out;
else
right_shift <= {1'b0,left_shift[7:1]};
end
串并转换实现:
简单的串转并
verilog desigen example
//简单的串转并变换如下:
always@(posedge clk)
dout <= {dout[6:0],din};//高位先发的情况
// dout <= {din,dout[7:1]}; //低位先发的情况
//串并转换,转换成N位的并行数据需要N个时间,实际使用时作用的是一帧一帧数据,如果单独的通过串并转换可能并非是一帧数据,也就是说以8位为1组完成串并转换,如果数据连续发送这时候可以通过利用一组乒乓模式完成串并转换,当一帧数据发送完毕时乒一帧数据的寄存器归零,乓一帧数据的寄存器开始发送,当然如果数据不是连续发送则可以通过一帧数据发送完毕将寄存器归零等待下次发送
下面模拟一下连续发送模式下的乒乓转换模式,可以使用状态机完成也可以使用两组时序逻辑块完成
module pingpang(
input clk,
input rstn,
input en,
input din,
output [7:0] dout
);
reg [2:0] state,n_state;
reg [3:0] cnt;
reg cnt_en;
reg done;
reg [7:0] dout_reg;
parameter idle = 3'b001,
ping = 3'b010,
pang = 3'b100;
always@(posedge clk or negedge rstn)
begin
if(~rstn)
state <= idle;
else
state <= n_state;
end
always@(posedge clk)
begin
if(cnt_en)
cnt <= cnt+1;
else
cnt <= 4'd0;
end
always@(posedge clk or negedge rstn)
begin
if(~rstn)
done <= 1'b0;
else if (cnt == 4'd7)
done <= 1'b1;
else
done <= 1'b0;
end
always@(*)
begin
if(~rstn)
n_state <= idle;
else
case(state)
idle:
begin
if(en)
begin
n_state <= ping;
cnt_en <= 1'b1;
end
else
begin
n_state <= idle;
cnt_en <= 1'b0;
end
end
ping:
begin
if(!en)
begin
n_state <= idle;
cnt_en <= 1'b0;
end
else if (cnt == 4'd7)
begin
n_state <= pang;
cnt_en <= 1'b0;
end
else
begin
n_state <= ping;
cnt_en <= 1'b1;
end
end
pang:
begin
if(!en)
begin
n_state <= idle;
cnt_en <= 1'b0;
end
else if(cnt == 4'd7)
begin
n_state <= ping;
cnt_en <= 1'b0;
end
else
begin
n_state <= pang;
cnt_en <= 1'b1;
end
end
default:
begin
n_state <= idle;
cnt_en <= 1'b0;
end
endcase
end
always@(posedge clk or negedge rstn)
begin
if(~rstn)
dout_reg <= 8'b0;
else if(en)
dout_reg[cnt] <= din;
else
dout_reg <= dout_reg;
end
assign dout = (done)?dout_reg:dout;
endmodule
连续传输模式下的串转并tb如下
module tb_pingpang(
);
// pingpang Parameters
parameter PERIOD = 10 ;
parameter idle = 3'b001;
// pingpang Inputs
reg clk = 0 ;
reg rstn = 0 ;
reg en = 0 ;
reg din = 0 ;
// pingpang Outputs
wire [7:0] dout ;
initial
begin
forever #(PERIOD/2) clk=~clk;
end
initial
begin
#(PERIOD*2) rstn = 1;
end
pingpang #(
.idle ( idle ))
u_pingpang (
.clk ( clk ),
.rstn ( rstn ),
.en ( en ),
.din ( din ),
.dout ( dout [7:0] )
);
initial
begin
#(PERIOD*5) en <= 1'b1;
end
initial
begin
#(45)din <= 1;
#(PERIOD) din <= 1;
#(PERIOD) din <= 0;
#(PERIOD) din <= 1;
#(PERIOD) din <= 1;
#(PERIOD) din <= 0;
#(PERIOD) din <= 0;
#(PERIOD) din <= 1;
//一帧
#(PERIOD) din <= 0;
#(PERIOD) din <= 1;
#(PERIOD) din <= 0;
#(PERIOD) din <= 0;
#(PERIOD) din <= 0;
#(PERIOD) din <= 0;
#(PERIOD) din <= 1;
#(PERIOD) din <= 0;
//一帧
#(PERIOD) din <= 1;
#(PERIOD) din <= 1;
#(PERIOD) din <= 0;
#(PERIOD) din <= 0;
#(PERIOD) din <= 0;
#(PERIOD) din <= 0;
#(PERIOD) din <= 1;
end
endmodule
自同步过程中的时钟恢复通过锁相环合成与生成输入串行数据流的相匹配的时钟