串行发送电路有着比较广泛的应用,比如USB、SATA、SPI......串行发送电路涉及到的问题包括:高位先或低位先、数据开始标志、校验位纠错等问题。在本文中,以实现具有奇校验功能的串行发送电路为例,介绍基于有限状态机和移位寄存器两种实现方法。
例:具有奇校验功能的串行发送电路
1、 电路输入1个时钟周期宽度的输入数据有效脉冲strobe,8位数据输入din。strobe为高电平期间输入数据有效。
2、电路把输入的数据按从高到低的顺序依次从dout发送出去。
3、在发送完8位数据后发送一位的奇校验位。
注:奇校验P=not(D(n) xorD(n-1) xorD(n-2) xor… xorD2 xorD1 xorD0)
方法一 基于移位寄存器实现具有奇校验功能的串行发送电路
这种方法是思路最为简单最容易理解的一种方式,采用9个寄存器级联,分别用于存储8位数据和1位奇校验码。
其对应的电路结构如下:
一个designer看到上面的电路结构图都能很轻易写出如下RTL代码如下:
module transmission_circuit_1(
clk,
rst,
din,
strobe,
dout);
input [7:0]din;
input clk,rst,strobe;
output dout;
reg dout;
reg[7:0]temp;
wire p;
reg [3:0]count;
always@(posedge clk or negedge rst)
begin
if(!rst)
begin
temp<=0;
dout<=0;
count<=0;
end
else if(strobe==1)
begin
temp[0]<=din[0];
temp[1]<=din[1];
temp[2]<=din[2];
temp[3]<=din[3];
temp[4]<=din[4];
temp[5]<=din[5];
temp[6]<=din[6];
temp[7]<=din[7];
dout<=0;
count<=0;
end
else if(count<=8)
begin
temp[0]<=p;
temp[1]<=temp[0];
temp[2]<=temp[1];
temp[3]<=temp[2];
temp[4]<=temp[3];
temp[5]<=temp[4];
temp[6]<=temp[5];
temp[7]<=temp[6];
dout<=temp[7];
count<=count+1;
end
else
dout<=0;
end
assign p=~(temp[7]^temp[6]^temp[5]^temp[4]^temp[3]^temp[2]^temp[1]^temp[0]);
endmodule
对于奇校验码
p=~(temp[7]^temp[6]^temp[5]^temp[4]^temp[3]^temp[2]^temp[1]^temp[0]);
随着移位寄存器的移位temp的值是不断发生变化的,所以需要一个count移位9次就停止,否则后面输出的值就会发生紊乱。由此,我们希望能够在strobe为1时就将p和din一次性存上,之后(strobe=1)时移位寄存器的输入就保持为0,所以增加一个寄存器构成10位移位寄存器,并且改变校验位的产生方式,如下:
p=~(din[7]^din[6]^din[5]^din[4]^din[3]^din[2]^din[1]^din[0]);
代码优化
module transmission_circuit_1(
clk,
rst,
din,
strobe,
dout);
input [7:0]din;
input clk,rst,strobe;
output dout;
reg dout;
reg[7:0]temp;
reg dp;
wire p;
always@(posedge clk or negedge rst)
begin
if(!rst)
begin
temp<=0;
dout<=0;
dp<=0;
end
else if(strobe==1)
begin
dp<=p;
temp[0]<=din[0];
temp[1]<=din[1];
temp[2]<=din[2];
temp[3]<=din[3];
temp[4]<=din[4];
temp[5]<=din[5];
temp[6]<=din[6];
temp[7]<=din[7];
dout<=0;
end
else
begin
dp<=0;
temp[0]<=dp;
temp[1]<=temp[0];
temp[2]<=temp[1];
temp[3]<=temp[2];
temp[4]<=temp[3];
temp[5]<=temp[4];
temp[6]<=temp[5];
temp[7]<=temp[6];
dout<=temp[7];
end
end
assign p=~(din[7]^din[6]^din[5]^din[4]^din[3]^din[2]^din[1]^din[0]);
endmodule
方法二 基于有限状态机实现具有奇校验功能的串行发送电路
基于寄存器传输级描述电路,硬件通常可以分为控制单元和数据路径两类。其中控制单元通常用有限状态机来描述。
module transmission_circuit(
clk,
rst,
din,
strobe,
dout);
input [7:0] din;
input clk,rst;
input strobe;
output dout;
reg dout;
parameter[4:0]
S0=0,
S1=1,
S2=2,
S3=3,
S4=4,
S5=5,
S6=6,
S7=7,
S8=8,
S9=9;
reg[4:0] c_s,n_s;
reg[7:0] temp;
wire p;
always@(posedge clk or negedge rst)
begin
if (!rst)
c_s<=S0;
else
c_s<=n_s;
end
always @(strobe or c_s or temp or din)
begin
case (c_s)
S0: begin
if (strobe==1)
begin
n_s=S1;
// temp=din;
end
else
n_s=S0;
end
S1: n_s=S2;
S2: n_s=S3;
S3: n_s=S4;
S4: n_s=S5;
S5: n_s=S6;
S6: n_s=S7;
S7: n_s=S8;
S8: n_s=S9;
S9: n_s=S0;
default:n_s=S0;
endcase
end
always@(posedge clk or negedge rst)
begin
if(!rst)
temp<=0;
else if(c_s==S0 && strobe==1)
temp<=din;
end
always@(posedge clk or negedge rst)
begin
if (!rst)
begin
dout<=0;
temp<=0;
end
else if (c_s==S1)
dout<=temp[7];
else if (c_s==S2)
dout<=temp[6];
else if (c_s==S3)
dout<=temp[5];
else if (c_s==S4)
dout<=temp[4];
else if (c_s==S5)
dout<=temp[3];
else if (c_s==S6)
dout<=temp[2];
else if (c_s==S7)
dout<=temp[1];
else if (c_s==S8)
dout<=temp[0];
else if (c_s==S9)
dout<=p;
else
dout<=0;
end
assign p=~(din[7]^din[6]^din[5]^din[4]^din[3]^din[2]^din[1]^din[0]);
endmodule
小结:通常对于数据的串/并输入输出的问题处理采用以上两种方法进行处理,其中移位寄存器的处理方法思路清晰,代码简单,处理此类问题更具有优势,而有限状态机能够处理任意类型的电路结构。一个优秀的设计者一定是用最小的硬件开销就能实现电路功能。