在上篇文章中,我们讨论并实现了加性/加扰的算法,原理,以及实现方式。在文章中,揭示了算法的实现,设计了利用加扰,解扰演示实例,但是这个演示实例不是非常完善通信工程(目的是演示加扰,解扰的算法)。对于接收端的通讯实现,需要发送端的同步信号,这种方法对于真实的通讯来说,是很难实现的(发送端和接收端都是异步通讯的)。本文中将修改之前的工程,增加preamble + SFD , 实现工程收发同步。 这样,在接收端就可以利用preamble + SFD 所提供的同步信息, 提取出同步字,实现解扰的算法。
仿真工程代码:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
`timescale 1 ns / 1 ps module tb ( ); parameter SYNC1 = 8'b1010_1010; parameter SYNC2 = 8'b1010_1011; parameter PERIOD = 20 ; //周期20 reg pll_rst; //实体模块PLL的rst信号 wire tx_rx; // 收发在testbench的回环信号 wire clk_100M; wire pll_locked; //实体PLL锁定信号 wire rst = !pll_locked; //Testbench内生成复位信号 reg [ 7: 0 ] tx_data; //待发送数据 wire rx_vld; wire rx_rdy; wire [ 7: 0 ] rx_data; reg inclk ; // 模拟板级提供的输入时钟 reg [ 2: 0 ] tx_st; initial begin inclk = 1'b0; #( PERIOD / 2 ); forever #( PERIOD / 2 ) inclk = ~inclk; end //always #10 inclk=~inclk; initial begin pll_rst = 1'b1; tx_data = 0; #50 pll_rst = 1'b0; end wire tx_rdy; reg tx_vld = 0; reg tx_en = 0; reg [5:0] send_cnt = 0; always@( posedge clk_100M or posedge rst ) if ( rst ) begin tx_en <= 0; tx_st <= 0; tx_data <= 0; end else begin case ( tx_st ) 0: begin tx_en <= 0; send_cnt <= 0; tx_data <= 0; tx_vld <= 0; tx_st <= 1; end 1: begin tx_vld <= 1; tx_st <= 2; end 2: begin if(tx_rdy) begin tx_data <= 0; tx_en <= 1; send_cnt <= send_cnt + 1; // if(send_cnt == 7) tx_st <= 3; end end 3: begin tx_en <= 0; if(tx_rdy) begin tx_en <= 1; tx_data <= tx_data + 1; send_cnt <= send_cnt + 1; // if ( send_cnt == 23 ) if ( send_cnt == 31 ) begin send_cnt <= 0; tx_st <= 7; end end end 6: begin if(tx_rdy) begin tx_data <= 8'hff; send_cnt <= send_cnt + 1; if(send_cnt == 31) begin send_cnt <= 0; tx_st <= 7; end end end 7: begin tx_en <= 0; tx_vld <= 0; send_cnt <= send_cnt + 1; if(&send_cnt) begin tx_st <= 0; end end default: tx_st <= 0; endcase end hs_txrx hs_txrx_inst ( .inclk ( inclk ), .pll_rst ( pll_rst ), .tx_data ( tx_data ), .tx_en ( tx_en ), .tx_rdy ( tx_rdy ), .tx_vld ( tx_vld ), .tx ( tx_rx ), .rx ( tx_rx ), .rx_vld ( rx_vld ), .rx_rdy ( rx_rdy ), .rx_data ( rx_data ), .clk_100M ( clk_100M ), .pll_locked ( pll_locked ) ); endmodule |
顶层文件:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
module hs_txrx #( parameter SCRAMB_SYNC = 15'b000_0000_1010_1001, parameter SYNC1 = 8'b1010_1010, parameter SYNC2 = 8'b1010_1011 ) ( input inclk, input pll_rst, input [ 7: 0 ] tx_data, input tx_en, output tx_rdy, input tx_vld, output tx, input rx, output rx_rdy, output rx_vld, output [ 7: 0 ] rx_data, output clk_100M, output pll_locked ); wire clk_400M; wire rst = !pll_locked; trans_data #( .SCRAMB_SYNC(SCRAMB_SYNC), .SYNC1( SYNC1 ), .SYNC2( SYNC2 ) ) trans_data_inst ( .rst ( rst ), .clk_100M ( clk_100M ), .tx_data ( tx_data ), // 100M的时钟对应的数据 .tx_en ( tx_en ), .tx_vld ( tx_vld ), .tx_rdy ( tx_rdy ), .tx_out ( tx ) ); rev_pcs #( .SCRAMB_SYNC( SCRAMB_SYNC ), .SYNC1( SYNC1 ), .SYNC2( SYNC2 ) ) recv_pcs_inst ( .rst ( rst ), .clk_100M ( clk_100M ), .clk_400M ( clk_400M ), .rx_vld ( rx_vld ), .rx_data ( rx_data ), .rx_rdy ( rx_rdy ), .rx ( rx ) ); pll1 pll1_inst ( .areset ( pll_rst ), //1'b0; .inclk0 ( inclk ), .c0 ( clk_10M ), .c1 ( clk_100M ), .c2 ( clk_400M ), .locked ( pll_locked ) ); endmodule |
trans_data.v文件:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
module trans_data #( parameter SCRAMB_SYNC = 15'b000_0000_1010_1001, parameter SYNC1 = 8'b1010_1010, parameter SYNC2 = 8'b1010_1011 ) ( input rst, input clk_100M, output reg tx_rdy = 0, input tx_vld, input tx_en, input [ 7: 0 ] tx_data, // 100M的时钟对应的数据 output tx_out ); reg [ 14: 0 ] scrambler; reg scb_en = 0; reg [7:0] scb_bit_vector = 0; integer i; always@( posedge clk_100M ) if ( ~tx_vld ) begin scb_bit_vector = 0; scrambler = SCRAMB_SYNC; end else if(scb_en) begin for (i = 0; i < 8; i = i + 1) begin scb_bit_vector[ i ] = scrambler[ 14 ] ^ scrambler[ 13 ]; scrambler = {scrambler[13:0], scb_bit_vector[ i ]}; end end reg [7:0] tx_pma_in = 0; reg tx_pma_en = 0; wire tx_pma_req; reg [ 2: 0 ] scb_st; always@( posedge clk_100M or posedge rst ) if ( rst ) begin scb_st <= 0; tx_rdy <= 0; end else begin case ( scb_st ) 0: begin tx_pma_en <= 0; tx_rdy <= 1'b0; tx_pma_in <= SYNC1; if ( tx_vld) begin scb_st <= 1; end end 1: begin tx_pma_en <= 0; if(tx_pma_req) begin tx_pma_en <= 1; tx_pma_in <= SYNC1; scb_st <= 2; end end 2: begin tx_rdy <= 0; tx_pma_en <= 0; if(tx_pma_req) begin tx_pma_en <= 1; tx_pma_in <= SYNC2; tx_rdy <= 1; scb_en <= 1; scb_st <= 3; end end 3: begin tx_rdy <= 0; scb_en <= 0; tx_pma_en <= 0; if ( tx_pma_req ) begin tx_pma_en <= 1; tx_pma_in <= tx_data ^ scb_bit_vector; scb_en <= 1; if ( ~tx_vld ) scb_st <= 4; else tx_rdy <= 1; end end 4: begin scb_en <= 0; tx_rdy <= 0; tx_pma_en <= 0; if(tx_pma_req) begin tx_pma_en <= 1; tx_pma_in <= SYNC1; scb_st <= 0; end end default: scb_st <= 0; endcase end trans_pma #( .SCRAMB_SYNC(SCRAMB_SYNC), .SYNC1 (SYNC1), .SYNC2 (SYNC2) ) trans_pma_inst ( .clk_100M ( clk_100M ), .tx_pma_en ( tx_pma_en ), .tx_pma_req ( tx_pma_req ), .tx_pma_in ( tx_pma_in ), .tx_out ( tx_out ), .rst ( rst) ); endmodule |
trans_pma.v
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
module trans_pma #( parameter SCRAMB_SYNC = 15'b000_0000_1010_1001, parameter SYNC1 = 8'b1010_1010, parameter SYNC2 = 8'b1010_1011 ) ( input clk_100M, input tx_pma_en, output reg tx_pma_req = 0, input [ 7: 0 ] tx_pma_in, // 100M的时钟对应的数据 output tx_out, input rst ); reg [7:0] tx_data_temp; always@( posedge clk_100M or posedge rst ) if(rst) tx_data_temp <= 8'b1010_1010; else if ( tx_pma_en ) tx_data_temp <= tx_pma_in; reg [7:0] tx_shift; reg [2:0] tx_cnt = 0; wire tx_pma_reload = (tx_cnt == 7) ? 1'b1 : 1'b0; always@( posedge clk_100M or posedge rst ) if(rst) begin tx_pma_req <= 0; tx_shift <= 8'b1010_1010; tx_cnt <= 0; end else begin tx_pma_req <= 0; if ( tx_pma_reload ) begin tx_pma_req <= 1; tx_shift <= tx_data_temp; end else tx_shift <= {tx_shift[ 0 ], tx_shift[ 7: 1 ]}; tx_cnt <= tx_cnt + 1; end // pmd IO_TX IO_TX_inst ( .tx_in ( tx_shift[0] ), .tx_out ( tx_out ) ); endmodule |
rec_pcs.v
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
module rev_pcs #( parameter SCRAMB_SYNC = 15'b000_0000_1010_1001, parameter SYNC1 = 8'b1010_1010, parameter SYNC2 = 8'b1010_1011 ) ( input rx, output reg rx_vld = 0, output rx_rdy, output reg [ 7: 0 ] rx_data, input clk_100M, input clk_400M, input rst ); wire sync; wire [7:0] rx_data_scb ; reg [ 14: 0 ] scrambler; wire scb_en; reg [7:0] scb_bit_vector = 0; integer i; always@( posedge clk_100M ) if ( ~sync ) begin scb_bit_vector = 0; scrambler = SCRAMB_SYNC; end else if(scb_en) begin for (i = 0; i < 8; i = i + 1) begin scb_bit_vector[ i ] = scrambler[ 14 ] ^ scrambler[ 13 ]; scrambler = {scrambler[13:0], scb_bit_vector[ i ]}; end end recv_data #( .SYNC1( SYNC1 ), .SYNC2( SYNC2 ) ) recv_data_inst ( .rst ( rst ), .clk_100M ( clk_100M ), .clk_400M ( clk_400M ), .sync ( sync ), .rx ( rx ), .rx_data_100Mr ( rx_data_scb ), .rx_data_vld_100Mr( scb_en ) ); reg [1:0] rx_vld_r = 0; always @ (posedge clk_100M) begin rx_vld_r <= {rx_vld_r[0], scb_en}; end always @ (posedge clk_100M) if(rx_vld_r[0]) begin rx_data = rx_data_scb ^ scb_bit_vector; end always @ (posedge clk_100M) if(sync) rx_vld <= 1; else if(rx_rdy) rx_vld <= 0; assign rx_rdy = rx_vld_r[1]; endmodule |
recv_data.v
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
module recv_data #( parameter SYNC1 = 8'b1010_1010, parameter SYNC2 = 8'b1010_1011 ) ( input rst, input clk_100M, input clk_400M, input rx, output reg sync = 0, output reg[ 7: 0 ] rx_data_100Mr, output reg rx_data_vld_100Mr ); wire rx_bit; wire rx_bit_vld; reg [ 3: 0 ] bit_count; reg [ 7: 0 ] bit_sft; reg [ 7: 0 ] sync_shift = 0; reg fr_sync1, fr_sync2; reg fr_sync; always @ (posedge clk_100M) sync <= fr_sync; reg fr_end; reg [ 7: 0 ] fr_count; reg[ 7: 0 ] rx_data; reg rx_data_vld_tmp; always@( posedge clk_400M or posedge rst ) if ( rst ) begin rx_data <= 0; rx_data_vld_tmp <= 0; bit_count <= 0; bit_sft <= 0; fr_sync1 <= 0; fr_sync2 <= 0; fr_sync <= 0; fr_end <= 0; fr_count <= 0; end else begin if ( rx_bit_vld ) begin bit_sft <= { rx_bit, bit_sft[ 7: 1 ]}; sync_shift <= { bit_sft[ 0 ], sync_shift[ 7: 1] }; end if ( fr_sync ) fr_sync2 <= 1'b0; else if ( bit_sft == SYNC2 ) fr_sync2 <= 1'b1; //fr----frame else fr_sync2 <= 1'b0; if ( fr_sync ) fr_sync1 <= 1'b0; else if ( sync_shift == SYNC1 ) fr_sync1 <= 1'b1; else fr_sync1 <= 1'b0; if ( fr_end ) fr_sync <= 1'b0; else if ( fr_sync1 & fr_sync2 & rx_bit_vld ) fr_sync <= 1'b1; if ( fr_sync ) begin if ( rx_bit_vld ) begin if ( bit_count == 7 ) bit_count <= 0; else bit_count <= bit_count + 1; end end rx_data_vld_tmp <= 0; if ( bit_count == 7 ) begin rx_data <= bit_sft; rx_data_vld_tmp <= 1'b1; end fr_end <= 1'b0; if ( rx_data_vld_tmp & rx_bit_vld ) if ( fr_count == 31 ) begin fr_end <= 1'b1; fr_count <= 0; end else fr_count <= fr_count + 1; end wire rx_data_vld = rx_data_vld_tmp & rx_bit_vld; reg rx_data_vld_r; reg [ 5: 0 ] count_400M; reg rx_data_vld_x; reg nrx_data_vld_x; reg rx_data_vld_xrg; always@( posedge clk_400M or posedge rst ) if ( rst ) begin count_400M <= 0; rx_data_vld_r <= 0; end else begin if ( rx_data_vld ) rx_data_vld_r <= 1'b1; else if ( count_400M == 15 ) rx_data_vld_r <= 1'b0; if ( count_400M == 15 ) count_400M <= 0; else if ( rx_data_vld_r ) count_400M <= count_400M + 1; end always@( posedge clk_100M or posedge rst ) if ( rst ) begin rx_data_vld_x <= 1'b0; nrx_data_vld_x <= 1'b1; rx_data_vld_xrg <= 1'b0; rx_data_100Mr <= 0; rx_data_vld_100Mr <= 1'b0; // rx_data_vld_100Mrr <= 1'b0; end else begin rx_data_vld_x <= rx_data_vld_r; nrx_data_vld_x <= !rx_data_vld_x; rx_data_vld_xrg <= nrx_data_vld_x & rx_data_vld_x; rx_data_vld_100Mr <= 1'b0; if ( rx_data_vld_xrg ) begin rx_data_100Mr <= rx_data; rx_data_vld_100Mr <= 1'b1; end end recv_bit recv_bit_inst ( .rst ( rst ), .clk_400M ( clk_400M ), .rx ( rx ), .rx_bit ( rx_bit ), .rx_bit_vld ( rx_bit_vld ) ); endmodule |
仿真结果:

图1
仿真程序中发送数据 8’h00, 8’h01, 8’h02, ….. 8’h1f , 接收端可以正常接收到8’h00, 8’h01, 8’h02, …. 8’h1f。

图2

图3
tx_pma_reload 将tx_data_temp (之前锁存的数据)装载到tx_shift 中, 同时发送tx_pma_req 请求下一个数据,只要下一个数据在reload之前准备好就可以了, 这样就给上层程序预留了很多时间(有一定的弹性)。
quartus 代码
[contend_control]
[/contend_control]
关于程序的更多讲解, 请参照视频文件。