在上节内容中讲解了串行通信中的帧结构,如每个帧的开始部分都会有前导字和帧起始(即Preamble+SFD)作为帧的标志,在帧同步时作为同步字搜索,接收端可以在搜索到关键字后进行帧同步。这个前导字不仅能提供短暂的直流平衡,还能提供足够的时钟信息,在位同步的解调中起到关键的作用。在自适应位同步的提取中(ACDR),有一个前提是在帧数据部分也应该有足够的边沿变化,而在源码的数据流中长0或长1的概率是非常高的,因此就要将通信中的源码进行变换,通常称为编码。这种用于改善信道的编码称为信道编码。信道编码通常有如下几种,加扰,4b/5b编码,8b/10b编码,64b/66b编码,128b/130b, 128b/132b等,其它几种编码已经在其它章节介绍过了,本节内容着重讲解加扰(Scrambler)编码以及其反变换–解扰(de-scrambler)等原理及使用。
1. 加扰
加扰的原理是在数据串行化时将串行数据流送入加扰器,通过加扰器的模2运算(异或运算)使得长0与长1消除。关于加扰的原理的相关知识,可以参考相关内容。加扰又分为两种,加性加扰和乘性加扰两种。加性加扰如图1所示,

图1 加性加扰器
- 加性加扰
加性加扰的特点是加扰器产生的模2运算的结果与输入数据再做模2运算,结果作为串行数据输出。加性加扰器有如下内容及特点:
(1)典型生成多项式 ,
G(X) = X15 + X14 + 1
G(X) = X23 + X18 + 1
(2) 运算前需要同步,即在一帧数据发送前应初始化加扰器如图1,在帧数据加扰前应将加扰器的寄存器初始化为1001_0101_0000_000, 例如
reg [14:0] sramb_sync = 15’b000_0000_1010_1001;
(3)输入数据不参与加扰器的寄存器移位,仅加扰器自身的模2加结果参与循环移位
(4)解扰器的生成多项式即运算过程与加扰器一致如图1,解扰器也需要帧初始化同步。同步控制一般采用帧起始(如preamble+SFD)或64b/66b的中66-bit的控制位(如01或10, 详细内容请参照64b/66b的内容).
例1, 利用生成多项式G(X) = X15 + X14 + 1 实现加性加扰与解码Verilog代码,并通过Modelsim进行验证。
发送端代码:
`timescale 1 ns /1 ps
module additive_scrambler_tx#
(
parameter SCRAMB_SYNC = 15'b000_0000_1010_1001
)
(
input sys_clk,
input rst,
input tx_start,
input tx_en,
input [ 7: 0 ] tx_data,
input tx_end,
output reg tx_rdy,
output reg tx_out
);
reg [ 14: 0 ] scrambler;
reg [ 7: 0 ] tx_shift;
reg [ 3: 0 ] shift_count;
wire scb_bit;
reg tx_end_r;
reg tx_end_ack;
always@( posedge sys_clk or posedge rst )
if ( rst )
tx_end_r <= 0;
else
begin
if ( tx_end )
tx_end_r <= 1'b1;
else if ( tx_end_ack )
tx_end_r <= 1'b0;
end
reg [ 2: 0 ] scb_st;
assign scb_bit = scrambler[ 14 ] ^ scrambler[ 13 ];
always@( posedge sys_clk or posedge rst )
if ( rst )
begin
scb_st <= 0;
scrambler <= SCRAMB_SYNC;
tx_shift <= 0;
shift_count <= 0;
tx_rdy <= 0;
tx_end_ack <= 0;
end
else
begin
case ( scb_st )
0:
begin
tx_rdy <= 1'b0;
tx_end_ack <= 0;
if ( tx_start )
begin
scb_st <= 1;
scrambler <= SCRAMB_SYNC;
end
end
1:
begin
tx_rdy <= 1'b1;
shift_count <= 0;
if ( tx_end )
scb_st <= 0;
else if ( tx_en )
begin
tx_shift <= tx_data;
shift_count <= shift_count + 1;
tx_rdy <= 1'b0;
scb_st <= 2;
end
end
2:
begin
tx_rdy <= 0;
scrambler <= { scrambler[ 13: 0 ], scb_bit };
if ( tx_en )
begin
tx_shift <= tx_data;
end
else
tx_shift <= { 1'b1, tx_shift[ 7: 1 ] };
if ( shift_count == 6 )
tx_rdy <= 1'b1;
if ( shift_count == 7 )
begin
shift_count <= 0;
if ( tx_end_r )
begin
scb_st <= 0;
tx_end_ack <= 1;
end
end
else
shift_count <= shift_count + 1;
end
default:
scb_st <= 0;
endcase
end
always@( posedge sys_clk or posedge rst )
if ( rst )
begin
tx_out <= 1'b1;
end
else
begin
tx_out <= tx_shift[ 0 ] ^ scb_bit;
end
endmodule
接收端代码:
`timescale 1 ns /1 ps
module additive_scrambler_rx#
(
parameter SCRAMB_SYNC = 15'b000_0000_1010_1001
)
(
input sys_clk,
input rst,
input rx_start,
input rx_en,
input rx_in,
input rx_end,
output reg rx_rdy,
output reg [ 7: 0 ] rx_data
);
reg [ 14: 0 ] scrambler;
reg [ 7: 0 ] rx_shift;
reg [ 3: 0 ] shift_count;
wire scb_bit;
wire rx_bit;
reg rx_rdy_tmp;
reg rx_end_r;
reg rx_end_ack;
reg [ 2: 0 ] scb_st;
assign scb_bit = scrambler[ 14 ] ^ scrambler[ 13 ];
assign rx_bit = rx_in ^ scb_bit;
always@( posedge sys_clk or posedge rst )
if ( rst )
rx_end_r <= 0;
else if ( rx_end )
rx_end_r <= 1'b1;
else if ( rx_end_ack )
rx_end_r <= 1'b0;
always@( posedge sys_clk or posedge rst )
if ( rst )
begin
scb_st <= 0;
scrambler <= SCRAMB_SYNC;
rx_shift <= 0;
shift_count <= 0;
rx_rdy_tmp <= 0;
rx_end_ack <= 1'b0;
end
else
begin
case ( scb_st )
0:
begin
rx_rdy_tmp <= 0;
rx_end_ack <= 1'b0;
if ( rx_start )
begin
scb_st <= 1;
scrambler <= SCRAMB_SYNC;
end
end
1:
begin
rx_rdy_tmp <= 0;
if ( rx_end )
scb_st <= 0;
else if ( rx_en )
begin
scb_st <= 2;
end
end
2:
begin
rx_rdy_tmp <= 1'b0;
scrambler <= { scrambler[ 13: 0 ], scb_bit };
rx_shift <= { rx_bit, rx_shift[ 7: 1 ] };
if ( shift_count == 7 )
begin
shift_count <= 0;
rx_rdy_tmp <= 1'b1;
if ( rx_end_r )
begin
rx_end_ack <= 1'b1;
scb_st <= 0;
end
end
else
shift_count <= shift_count + 1;
end
default:
scb_st <= 0;
endcase
end
always@( posedge sys_clk or posedge rst )
if ( rst )
begin
rx_data <= 0;
rx_rdy <= 0;
end
else
begin
rx_rdy <= rx_rdy_tmp;
if ( rx_rdy_tmp )
begin
rx_data <= rx_shift;
end
end
endmodule
发送接收组装代码:
`timescale 1 ns /1 ps
module additive_scrambler#
(
parameter SCRAMB_SYNC = 15'b000_0000_1010_1001
)
(
input sys_clk,
input rst,
input tx_start,
input tx_en,
input [ 7: 0 ] tx_data,
input tx_end,
output tx_rdy,
output [ 7: 0 ] rx_data,
output rx_rdy
);
wire tx_out;
reg rx_en;
wire rx_in = tx_out; //回环测试
always@( posedge sys_clk or posedge rst )
if ( rst )
begin
rx_en <= 0;
end
else
begin
if ( tx_end )
rx_en <= 0;
else if ( tx_en )
rx_en <= 1'b1;
end
additive_scrambler_tx#
(
.SCRAMB_SYNC( 15'b000_0000_1010_1001 )
)
additive_scrambler_tx_inst
(
.sys_clk ( sys_clk ),
.rst ( rst ),
.tx_start ( tx_start ),
.tx_en ( tx_en ),
.tx_data ( tx_data ),
.tx_end ( tx_end ),
.tx_rdy ( tx_rdy ),
.tx_out ( tx_out )
);
additive_scrambler_rx#
(
.SCRAMB_SYNC( 15'b000_0000_1010_1001 )
)
additive_scrambler_rx_inst
(
.sys_clk ( sys_clk ),
.rst ( rst ),
.rx_start ( tx_start ),
.rx_en ( rx_en ),
.rx_in ( rx_in ),
.rx_end ( tx_end ),
.rx_data ( rx_data ),
.rx_rdy ( rx_rdy )
);
endmodule
仿真代码:
`timescale 1 ns /1 ps
module tb ( );
parameter sramb_sync = 15'b000_0000_1010_1001;
reg sys_clk = 0;
always #5 sys_clk = ~sys_clk;
reg rst = 1'b1;
initial
begin
rst = 1'b1;
#15 rst = 1'b0;
end
wire [ 7: 0 ] rx_data;
wire rx_rdy;
//=====================additive scambler
wire tx_rdy;
reg [ 7: 0 ] tx_data;
reg tx_start;
reg tx_en;
reg tx_end;
reg [ 4: 0 ] tx_delay;
reg [ 7: 0 ] tx_count;
reg [ 1: 0 ] tx_st;
always@( posedge sys_clk or posedge rst )
if ( rst )
begin
tx_data <= 0;
tx_count <= 0;
tx_en <= 0;
tx_start <= 0;
tx_delay <= 0;
tx_end <= 0;
tx_st <= 0;
end
else
begin
case ( tx_st )
0:
begin
tx_start <= 1'b1;
tx_data <= 0;
tx_count <= 0;
tx_en <= 0;
tx_delay <= 0;
tx_st <= 1;
end
1:
begin
tx_start <= 1'b0;
if ( tx_rdy )
begin
tx_count <= tx_count + 1;
tx_en <= 1'b1;
tx_st <= 2;
end
end
2:
begin
tx_en <= 0;
if ( tx_count == 32 )
begin
tx_end <= 1'b1;
tx_st <= 3;
end
else
begin
// tx_count <= tx_count + 1;
tx_st <= 1;
end
if ( tx_count < 8 )
tx_data <= 0;
else if ( tx_count > 23 )
tx_data <= 8'hff;
else
tx_data <= tx_count;
end
3:
begin
tx_end <= 0;
if ( tx_delay == 31 )
tx_st <= 0;
else
tx_delay <= tx_delay + 1;
end
endcase
end
additive_scrambler#
(
.SCRAMB_SYNC( 15'b000_0000_1010_1001 )
)
additive_scrambler_inst
(
.sys_clk ( sys_clk ),
.rst ( rst ),
.tx_start ( tx_start ),
.tx_en ( tx_en ),
.tx_data ( tx_data ),
.tx_end ( tx_end ),
.tx_rdy ( tx_rdy ),
.rx_data ( rx_data ),
.rx_rdy ( rx_rdy )
);
endmodule

图1 tb仿真波形
图1 可以看出在加扰后接系统能正确解扰收发端的加扰数据,详细的加扰效果可以参考图2。

图2
图2 中显示了发送程序的加扰效果,红色框中在tx_data在一段时间都为0,但tx_out信号经过加扰后,出现0,1交替输出。

图3
图3中可以观察到在接收端rx_in, scb_bit, rx_bit之间的运算,以及scrambler 的移位过程。
上面的例子主要目的是演示了加扰后对发送串行流带来的效果,如图2, 同时对于加性加扰如何根据帧同步控制加扰器进行复位初始化,以及在发送和接收中实现加扰/解扰器的移位。在实际的异步通信中可以用Preamble+SFD实现帧同步,或采用64b/66b的2位控制字实现同步。
- 乘性加扰
与加性加扰不同的是乘性加扰不仅加扰器自身模2加后循环移位,而且输入数据流也参与模2运算后参与加扰计算,从这一点看数据流的输出与输入之间(历史数据)有相与的关系存在,因此称为乘性加扰。生成多项式为G(X) = X23 + X18 + 1的加扰器如图4所示。
乘性加扰是递归的。即加扰后的信号反馈到移位回路中。

图4
- 乘性解扰
与加性解扰不同,乘性解扰不需要同步和初始化,但乘性解扰不能使用加扰器进行解扰,这一点与加性加扰器有重大区别,从上的加性加扰和解扰可以看出,加性加扰与解扰使用同一套加扰器。而乘性解扰则是独立的逻辑电路,如图5所示。

图5
解扰器的特点是非递归的,即解扰后的信号不反馈到回路中去。
2 .乘性加扰与加性加扰相比有如下异同点:
-
- 加性加扰需要特定初始化值,乘性加扰不需要特定初始化值(可以为随机数)。
- 加性加扰需要同步复位,乘性加扰不需要同步复位
- 加性加扰器也加性解扰器,乘性加扰与解扰分别为不同时序逻辑电路,但生成多项式相同。
- 加性加扰循环移位寄存器不受输入信号的影响是移位寄存器模2运算移位的结果,乘性加扰器的输入参与模2运算并前馈到移位序列中,历史输入数据参与加扰运算。
- 乘性加扰由于不需要同步复位,因此在加扰和解扰时的逻辑设计相对简单。
3. 乘性加扰与解扰编程与测试
(1) 发送端乘性加扰物理层(phy)的代码mul_scrambler_phy.v
`timescale 1 ns /1 ps
module mul_scrambler_phy
(
input rst,
input sys_clk,
input tx_in,
output reg tx_out
);
reg [ 22: 0 ] scb_shift;
wire tx_tmp = tx_in ^ ( scb_shift[ 17 ] ^ scb_shift[ 22 ] );
always@( posedge sys_clk or posedge rst )
if ( rst )
begin
scb_shift <= 0;
tx_out <= 0;
end
else
begin
tx_out <= tx_tmp;
scb_shift <= { scb_shift[ 21: 0 ], tx_tmp };
end
endmodule
(2)接收端端乘性加扰物理层(phy)的代码mul_scrambler_phy.v
`timescale 1 ns /1 ps
module mul_descrambler_phy
(
input rst,
input sys_clk,
input rx_in,
output reg rx_out
);
reg [ 22: 0 ] scb_shift;
wire rx_tmp = rx_in ^ ( scb_shift[ 17 ] ^ scb_shift[ 22 ] );
always@( posedge sys_clk or posedge rst )
if ( rst )
begin
scb_shift <= 0;
rx_out <= 0;
end
else
begin
rx_out <= rx_tmp;
scb_shift <= { scb_shift[ 21: 0 ], rx_in };
end
endmodule
(3)发送端数据帧及串行化mul_scrambler.v
`timescale 1 ns /1 ps
module mul_scrambler#
(
parameter SYNC_PREABLE = 8'b1010_1010,
parameter SYNC_SFD = 8'b1010_1011
)
(
input rst,
input sys_clk,
input tx_start,
input [ 7: 0 ] tx_data,
input tx_en,
input tx_end,
output reg tx_rdy_r,
output tx_out
);
reg [ 7: 0 ] tx_data_r;
reg [ 7: 0 ] tx_sht;
reg [ 2: 0 ] tx_sht_count;
reg [ 2: 0 ] tx_st;
wire tx_bit = tx_sht[ 7 ];
reg tx_start_r;
reg tx_start_ack;
reg tx_en_r;
reg tx_en_ack;
reg tx_end_r;
reg tx_end_ack;
reg tx_rdy;
always@( posedge sys_clk or posedge rst )
if ( rst )
begin
tx_start_r <= 0;
tx_end_r <= 0;
tx_en_r <= 0;
tx_rdy_r <= 0;
end
else
begin
if ( tx_start )
tx_start_r <= 1'b1;
else if ( tx_start_ack )
tx_start_r <= 1'b0;
if ( tx_end )
tx_end_r <= 1'b1;
else if ( tx_end_ack )
tx_end_r <= 1'b0;
if ( tx_en )
tx_en_r <= 1'b1;
else if ( tx_en_ack )
tx_en_r <= 0;
tx_rdy_r <= tx_rdy;
end
always@( posedge sys_clk or posedge rst )
if ( rst )
begin
tx_data_r <= SYNC_PREABLE;
tx_sht <= SYNC_PREABLE;
tx_sht_count <= 0;
tx_rdy <= 1'b0;
tx_start_ack <= 0;
tx_end_ack <= 1'b0;
tx_en_ack <= 1'b0;
tx_st <= 0;
end
else
begin
case ( tx_st )
0:
begin
tx_data_r <= SYNC_PREABLE;
tx_sht <= tx_data_r;
tx_sht_count <= 0;
tx_rdy <= 1'b0;
tx_start_ack <= 0;
tx_end_ack <= 1'b0;
tx_en_ack <= 1'b0;
tx_st <= 1;
end
1:
begin
tx_rdy <= 1'b0;
if ( tx_sht_count == 7 )
begin
tx_sht <= tx_data_r;
tx_sht_count <= 0;
if ( tx_start_r )
begin
tx_data_r <= SYNC_SFD;
tx_start_ack <= 1'b1;
tx_en_ack <= 1'b1;
tx_rdy <= 1'b1;
tx_st <= 2;
end
end
else
begin
tx_sht <= { tx_sht[ 6: 0 ], 1'b0 };
tx_sht_count <= tx_sht_count + 1'b1;
end
end
2:
begin
tx_en_ack <= 1'b0;
tx_rdy <= 1'b0;
tx_start_ack <= 1'b0;
if ( tx_sht_count == 7 )
begin
tx_sht <= tx_data_r;
tx_sht_count <= 0;
if ( tx_en_r )
begin
tx_en_ack <= 1'b1;
tx_data_r <= tx_data;
tx_rdy <= 1'b1;
end
else if ( tx_end_r )
begin
tx_end_ack <= 1'b1;
tx_en_ack <= 1'b1;
tx_data_r <= SYNC_PREABLE;
tx_sht <= SYNC_PREABLE;
tx_st <= 0;
end
end
else
begin
tx_sht <= { tx_sht[ 6: 0 ], 1'b0 };
tx_sht_count <= tx_sht_count + 1'b1;
end
end
default:
tx_st <= 0;
endcase
end
mul_scrambler_phy mul_scrambler_phy
(
.rst ( rst ),
.sys_clk ( sys_clk ),
.tx_in ( tx_bit ),
.tx_out ( tx_out )
);
endmodule
(4)接收端串并转换及数据帧mul_descrambler.v
`timescale 1 ns /1 ps
module mul_descrambler#
(
parameter SYNC_PREABLE = 8'b1010_1010,
parameter SYNC_SFD = 8'b1010_1011
)
(
input rst,
input sys_clk,
input rx_in,
output reg[ 7: 0 ] rx_data,
output reg rx_rdy,
output reg fr_end
);
wire rx_out;
reg [ 4: 0 ] rx_count;
reg [ 2: 0 ] rx_bit_count;
reg [ 7: 0 ] bit_sft;
reg [ 7: 0 ] sync_shift;
reg fr_sync;
always@( posedge sys_clk or posedge rst )
if ( rst )
begin
bit_sft <= 0;
sync_shift <= 0;
rx_data <= 0;
rx_rdy <= 1'b0;
rx_bit_count <= 0;
rx_count <= 0;
fr_sync <= 0;
fr_end <= 0;
end
else
begin
bit_sft <= { bit_sft[ 6: 0 ], rx_out };
sync_shift <= { sync_shift[ 6: 0 ], bit_sft[ 7 ] };
if ( fr_end )
begin
fr_sync <= 1'b0;
end
else if ( ( bit_sft == SYNC_SFD ) && ( sync_shift == SYNC_PREABLE ) )
fr_sync <= 1'b1;
rx_rdy <= 1'b0;
if ( fr_sync )
begin
if ( rx_bit_count == 7 )
begin
rx_rdy <= 1'b1;
rx_data <= bit_sft;
rx_bit_count <= 0;
end
else
rx_bit_count <= rx_bit_count + 1;
end
fr_end <= 0;
if ( fr_end )
rx_bit_count <= 0;
else if ( rx_rdy )
begin
if ( rx_count == 31 )
begin
rx_count <= 0;
fr_end <= 1'b1;
end
else
rx_count <= rx_count + 1;
end
end
mul_descrambler_phy mul_descrambler_phy_inst
(
.rst ( rst ),
.sys_clk ( sys_clk ),
.rx_in ( rx_in ),
.rx_out ( rx_out )
);
endmodule
(5)收发合并comp_mul_scrabler.v
`timescale 1 ns /1 ps
module comp_mul_scrabler#
(
parameter SYNC_PREABLE = 8'b1010_1010,
parameter SYNC_SFD = 8'b1010_1011
)
(
input rst,
input sys_clk,
input tx_start,
output tx_rdy,
input [ 7: 0 ] tx_data,
input tx_en,
input tx_end,
output rx_vld,
output[ 7: 0 ] rx_data,
output rx_rdy,
output fr_end
);
wire tx_bit;
mul_scrambler#
(
.SYNC_PREABLE( SYNC_PREABLE ),
.SYNC_SFD ( SYNC_SFD )
)
mul_scrambler_inst
(
.rst ( rst ),
.sys_clk ( sys_clk ),
.tx_start ( tx_start ),
.tx_data ( tx_data ),
.tx_en ( tx_en ),
.tx_end ( tx_end ),
.tx_rdy_r ( tx_rdy ),
.tx_out ( tx_bit )
);
mul_descrambler#
(
.SYNC_PREABLE( SYNC_PREABLE ),
.SYNC_SFD ( SYNC_SFD )
)
mul_descrambler_inst
(
.rst ( rst ),
.sys_clk ( sys_clk ),
.rx_in ( tx_bit ), // feedback loop
.rx_data ( rx_data ),
.fr_end ( fr_end ),
.rx_rdy ( rx_rdy )
);
endmodule
(6)仿真程序tb.v
`timescale 1 ns /1 ps
module tb ( );
parameter sramb_sync = 15'b000_0000_1010_1001;
reg sys_clk = 0;
always #5 sys_clk = ~sys_clk;
reg rst = 1'b1;
initial
begin
rst = 1'b1;
#15 rst = 1'b0;
end
wire [ 7: 0 ] rx_data;
wire rx_rdy;
//=====================additive scambler
wire tx_rdy;
reg [ 7: 0 ] tx_data;
reg tx_start;
reg tx_en;
reg tx_end;
reg [ 4: 0 ] tx_delay;
reg [ 7: 0 ] tx_count;
reg [ 1: 0 ] tx_st;
always@( posedge sys_clk or posedge rst )
if ( rst )
begin
tx_data <= 0;
tx_count <= 0;
tx_en <= 0;
tx_start <= 0;
tx_delay <= 0;
tx_end <= 0;
tx_st <= 0;
end
else
begin
case ( tx_st )
0:
begin
tx_start <= 1'b1;
tx_data <= 0;
tx_count <= 0;
tx_en <= 0;
tx_delay <= 0;
tx_st <= 1;
end
1:
begin
tx_start <= 1'b0;
if ( tx_rdy )
begin
tx_en <= 1'b1;
tx_st <= 2;
end
end
2:
begin
tx_en <= 0;
if ( tx_count == 32 )
begin
tx_end <= 1'b1;
tx_st <= 3;
end
else
begin
tx_count <= tx_count + 1;
tx_st <= 1;
end
if ( tx_count < 8 )
tx_data <= 0;
else if ( tx_count > 23 )
tx_data <= 8'hff;
else
tx_data <= tx_count;
end
3:
begin
tx_end <= 0;
if ( tx_delay == 31 )
tx_st <= 0;
else
tx_delay <= tx_delay + 1;
end
endcase
end
additive_scrambler#
(
.SCRAMB_SYNC( 15'b000_0000_1010_1001 )
)
additive_scrambler_inst
(
.sys_clk ( sys_clk ),
.rst ( rst ),
.tx_start ( tx_start ),
.tx_en ( tx_en ),
.tx_data ( tx_data ),
.tx_end ( tx_end ),
.tx_rdy ( tx_rdy ),
.rx_data ( rx_data ),
.rx_rdy ( rx_rdy )
);
endmodule
(7) 仿真波形

图6 tb.v的仿真波形

图7 mul_scrambler.v 仿真波形

图8 mul_descrambler.v的仿真波形
乘性加扰及解扰工程代码下载:
[content_control]
[/content_control]
注:加性加扰,将上文中的第一个tb.v替代工程中的tb.v文件即可测试加性加扰/解扰的Verilog RTL 代码。更详细的解释请看对应的视频文件。