576 lines
18 KiB
Verilog
576 lines
18 KiB
Verilog
`timescale 1ns / 1ns
|
|
// * Engineer:
|
|
// * *************************************************** *
|
|
// * ███████╗ ██████╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗ *
|
|
// * ╚══███╔╝██╔═══██╗██╔══██╗██╔═══██╗██╔════╝ ██║ ██║ *
|
|
// * ███╔╝ ██║ ██║██████╔╝██║ ██║██║ ███╗███████║ *
|
|
// * ███╔╝ ██║ ██║██╔══██╗██║ ██║██║ ██║██╔══██║ *
|
|
// * ███████╗╚██████╔╝██║ ██║╚██████╔╝╚██████╔╝██║ ██║ *
|
|
// * ╚══════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ *
|
|
// * *************************************************** *
|
|
// * Create Date: 2023/12/18
|
|
// * Update Date: 2024/07/24
|
|
|
|
// NOTE: 接口中的hop_wait和参数GAP_LEN均是为了等待,hop是为了跳频切换,gap是为了满足帧同步延迟,!!!将hop_wait设置为0并不能去掉改状态
|
|
module Transmitter #(
|
|
parameter AGC_HEADER_LEN = 10586,
|
|
parameter FRAME_HEADER_LEN = 512,
|
|
parameter BLOCK_NUM = 42,
|
|
parameter PHASE1_LEN = 2880, // (32 cp + 256 sym)* 10 ( total 2880 valid sym)
|
|
parameter PREFIX_LEN = 32,
|
|
parameter CHU_SEQ_LEN = 256,
|
|
parameter GAP_LEN = 160
|
|
) (
|
|
// general
|
|
input wire clk,
|
|
input wire rst,
|
|
// control
|
|
input wire [ 2:0] speed_mode,
|
|
input wire send_data_ready,
|
|
input wire send_start,
|
|
output reg send_over,
|
|
// data
|
|
// source data from others
|
|
output wire clk_data_src,
|
|
input wire [31:0] tx_data_src_tdata,
|
|
output reg tx_data_src_tready,
|
|
input wire tx_data_src_tvalid,
|
|
|
|
output reg [ 3:0] hopping_freq,
|
|
output wire [11:0] ad9361_tx_data_i,
|
|
output wire [11:0] ad9361_tx_data_q,
|
|
input wire test,
|
|
// param from ps
|
|
input wire [15:0] hop_wait // this is the gap between 2 blocks freq (unit in clk period)
|
|
);
|
|
// ******** Wire & Reg ********
|
|
|
|
reg [15:0] cnt_agc_send; // agc symbols have been sent
|
|
reg [15:0] cnt_sym_send; // symbols have been sent
|
|
reg [15:0] cnt_blocks_send; // blocks have been sent
|
|
reg [15:0] cnt_wait; // wait cnt max 65535 period, 50M -> 1.3ms
|
|
reg [15:0] cnt_chu_send;
|
|
// fsm
|
|
reg [ 3:0] cs;
|
|
reg [ 3:0] ns;
|
|
localparam [3:0] S_IDLE = 4'd0;
|
|
localparam [3:0] S_SEND_AGC = 4'd1;
|
|
localparam [3:0] S_SEND_FRAME_HEADER = 4'd2;
|
|
localparam [3:0] S_SEND_CHU_POS = 4'd8;
|
|
localparam [3:0] S_SEND_CHU_NEG = 4'd9;
|
|
localparam [3:0] S_SEND_PHASE1 = 4'd3;
|
|
localparam [3:0] S_WAIT_HOP = 4'd5;
|
|
localparam [3:0] S_WAIT_GAP = 4'd6; // wait for freq switch
|
|
localparam [3:0] S_TEST = 4'd7;
|
|
|
|
reg [ 3:0] interp;
|
|
reg [ 3:0] cnt_interp;
|
|
reg [13:0] agc_addr;
|
|
wire [ 1:0] agc_data;
|
|
reg [ 8:0] mseqs_addr;
|
|
reg [ 8:0] mseqs_addr_d1;
|
|
reg [ 8:0] mseqs_addr_d2;
|
|
reg [ 7:0] chu_seq_addr = 0;
|
|
wire [31:0] chu_seq;
|
|
wire mseqs;
|
|
reg [31:0] bb_wave_out_i; // shape filter result
|
|
reg [31:0] bb_wave_out_q; // shape filter result
|
|
wire [31:0] bb_wave_out_i_interp16;
|
|
wire [31:0] bb_wave_out_q_interp16;
|
|
wire [31:0] bb_wave_out_i_interp8;
|
|
wire [31:0] bb_wave_out_q_interp8;
|
|
wire [31:0] bb_wave_out_i_interp4;
|
|
wire [31:0] bb_wave_out_q_interp4;
|
|
wire fir_tvalid_in; // shape filter input valid
|
|
wire hand_shake; // not used
|
|
reg [15:0] m_fir_tdata_i;
|
|
reg [15:0] m_fir_tdata_q;
|
|
reg [ 3:0] rtz; // return to zero
|
|
|
|
reg [12:0] addr_tx_test = 'd0;
|
|
wire [ 7:0] data_tx_test;
|
|
|
|
// ******** Assingment ********
|
|
|
|
assign clk_data_src = clk;
|
|
assign fir_tvalid_in = (cnt_interp == interp);
|
|
assign hand_shake = tx_data_src_tvalid && tx_data_src_tready; // not used
|
|
|
|
assign ad9361_tx_data_i = bb_wave_out_i[31-:12];
|
|
assign ad9361_tx_data_q = bb_wave_out_q[31-:12];
|
|
|
|
// ******** Logic Block ********
|
|
|
|
// fsm
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
cs <= S_IDLE;
|
|
end
|
|
else begin
|
|
cs <= ns;
|
|
end
|
|
end
|
|
// state transition
|
|
always @(*) begin
|
|
case (cs)
|
|
S_IDLE: begin
|
|
if (send_start) begin
|
|
ns = S_SEND_AGC;
|
|
end
|
|
else if (test) begin
|
|
ns = S_TEST;
|
|
end
|
|
else begin
|
|
ns = S_IDLE;
|
|
end
|
|
end
|
|
|
|
S_SEND_AGC: begin
|
|
if (cnt_sym_send == AGC_HEADER_LEN - 1 && fir_tvalid_in) begin
|
|
ns = S_SEND_FRAME_HEADER;
|
|
end
|
|
else begin
|
|
ns = S_SEND_AGC;
|
|
end
|
|
end
|
|
|
|
S_SEND_FRAME_HEADER: begin
|
|
if (cnt_sym_send == FRAME_HEADER_LEN - 1 && fir_tvalid_in) begin
|
|
`ifdef TX_FRAME_WITH_GAP
|
|
ns = S_WAIT_GAP;
|
|
`else
|
|
ns = S_SEND_CHU_POS;
|
|
`endif
|
|
end
|
|
else begin
|
|
ns = S_SEND_FRAME_HEADER;
|
|
end
|
|
end
|
|
|
|
S_WAIT_GAP: begin
|
|
if (cnt_wait == GAP_LEN - 1) begin
|
|
ns = S_SEND_CHU_POS;
|
|
end
|
|
else begin
|
|
ns = S_WAIT_GAP;
|
|
end
|
|
end
|
|
|
|
S_SEND_CHU_POS: begin
|
|
if (cnt_chu_send == CHU_SEQ_LEN + PREFIX_LEN - 1 && fir_tvalid_in) begin
|
|
ns = S_SEND_CHU_NEG;
|
|
end
|
|
else begin
|
|
ns = S_SEND_CHU_POS;
|
|
end
|
|
end
|
|
|
|
S_SEND_CHU_NEG: begin
|
|
if (cnt_chu_send == CHU_SEQ_LEN + PREFIX_LEN - 1 && fir_tvalid_in) begin
|
|
ns = S_SEND_PHASE1;
|
|
end
|
|
else begin
|
|
ns = S_SEND_CHU_NEG;
|
|
end
|
|
end
|
|
|
|
S_SEND_PHASE1: begin
|
|
if (cnt_sym_send == PHASE1_LEN - 1 && fir_tvalid_in) begin
|
|
// send block num - 1 and send the final block
|
|
if (cnt_blocks_send == BLOCK_NUM) begin
|
|
ns = S_IDLE;
|
|
end
|
|
else begin
|
|
`ifdef TX_FRAME_WITH_GAP
|
|
ns = S_WAIT_HOP;
|
|
`else
|
|
ns = S_SEND_CHU_POS;
|
|
`endif
|
|
end
|
|
end
|
|
else begin
|
|
ns = S_SEND_PHASE1;
|
|
end
|
|
end
|
|
|
|
S_WAIT_HOP: begin
|
|
if (cnt_wait == hop_wait - 1) begin
|
|
ns = S_SEND_CHU_POS;
|
|
end
|
|
else begin
|
|
ns = S_WAIT_HOP;
|
|
end
|
|
end
|
|
|
|
S_TEST: begin
|
|
if (~test) begin
|
|
ns = S_IDLE;
|
|
end
|
|
else begin
|
|
ns = S_TEST;
|
|
end
|
|
end
|
|
default: begin
|
|
ns = S_IDLE;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
// speed mode select
|
|
always @(*) begin
|
|
case (speed_mode)
|
|
3'd0: begin
|
|
interp = 4'd15; // 16
|
|
bb_wave_out_i = bb_wave_out_i_interp16;
|
|
bb_wave_out_q = bb_wave_out_q_interp16;
|
|
end
|
|
3'd1: begin
|
|
interp = 4'd7; // 8
|
|
bb_wave_out_i = bb_wave_out_i_interp8;
|
|
bb_wave_out_q = bb_wave_out_q_interp8;
|
|
end
|
|
3'd2: begin
|
|
interp = 4'd3; // 4
|
|
bb_wave_out_i = bb_wave_out_i_interp4;
|
|
bb_wave_out_q = bb_wave_out_q_interp4;
|
|
end
|
|
// 3'd3: begin
|
|
// interp = 4'd1; // 2
|
|
// end
|
|
default: begin
|
|
interp = 4'd15;
|
|
bb_wave_out_i = bb_wave_out_i_interp16;
|
|
bb_wave_out_q = bb_wave_out_q_interp16;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
// tx_data_src_tready for handshake
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
tx_data_src_tready <= 1'd0;
|
|
end
|
|
// only when the phase 1 state , the transmitter will receive the data from outside(axis protocal)
|
|
else if (cs == S_SEND_PHASE1) begin
|
|
if (!tx_data_src_tready && tx_data_src_tvalid) begin // no handshake
|
|
if (fir_tvalid_in) begin
|
|
tx_data_src_tready <= 1'd1;
|
|
end
|
|
end
|
|
else begin
|
|
tx_data_src_tready <= 1'd0;
|
|
end
|
|
end
|
|
else begin
|
|
tx_data_src_tready <= 1'd0;
|
|
end
|
|
end
|
|
|
|
// interpolation counter
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
cnt_interp <= 4'd0;
|
|
end
|
|
else if (cs == S_IDLE && rtz == 4'd0) begin
|
|
cnt_interp <= 4'd0;
|
|
end
|
|
else if (cs == S_SEND_AGC || cs == S_SEND_FRAME_HEADER || cs == S_SEND_PHASE1 || cs == S_SEND_CHU_POS || cs == S_SEND_CHU_NEG || cs == S_TEST || rtz > 4'd0) begin
|
|
if (cnt_interp < interp) begin
|
|
cnt_interp <= cnt_interp + 4'd1;
|
|
end
|
|
else begin
|
|
cnt_interp <= 4'd0;
|
|
end
|
|
end
|
|
else begin
|
|
cnt_interp <= 4'd0;
|
|
end
|
|
end
|
|
|
|
// return to zero
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
rtz <= 4'd0;
|
|
end
|
|
else if (cs == S_SEND_AGC || cs == S_SEND_FRAME_HEADER || cs == S_SEND_PHASE1 || cs == S_SEND_CHU_POS || cs == S_SEND_CHU_NEG || cs == S_TEST) begin
|
|
if (ns == S_WAIT_HOP || ns == S_WAIT_GAP || ns == S_IDLE) begin
|
|
rtz <= 4'd1;
|
|
end
|
|
else begin
|
|
rtz <= 4'd0;
|
|
end
|
|
end
|
|
else if (fir_tvalid_in) begin
|
|
if (rtz == 4'd7) begin
|
|
rtz <= 4'd0;
|
|
end
|
|
else begin
|
|
rtz <= rtz + 4'd1;
|
|
end
|
|
end
|
|
end
|
|
|
|
//cnt_sym_send
|
|
always @(posedge clk) begin
|
|
if (rst || ns != cs) begin
|
|
cnt_sym_send <= 16'd0;
|
|
end
|
|
else if (cs == S_SEND_AGC || cs == S_SEND_FRAME_HEADER || cs == S_SEND_PHASE1 || cs == S_TEST) begin
|
|
if (fir_tvalid_in) begin
|
|
cnt_sym_send <= cnt_sym_send + 16'd1;
|
|
end
|
|
else begin
|
|
cnt_sym_send <= cnt_sym_send;
|
|
end
|
|
end
|
|
else begin
|
|
cnt_sym_send <= 16'd0;
|
|
end
|
|
end
|
|
|
|
// truncation
|
|
always @(*) begin
|
|
if (cs == S_SEND_AGC) begin
|
|
m_fir_tdata_i = agc_data[0] ? 16'h8001 : 16'h7FFF;
|
|
m_fir_tdata_q = agc_data[1] ? 16'h8001 : 16'h7FFF;
|
|
end
|
|
else if (cs == S_SEND_FRAME_HEADER) begin
|
|
m_fir_tdata_i = mseqs ? 16'h8001 : 16'h7FFF;
|
|
m_fir_tdata_q = mseqs ? 16'h8001 : 16'h7FFF;
|
|
end
|
|
else if (cs == S_SEND_PHASE1) begin
|
|
m_fir_tdata_i = tx_data_src_tdata[15-:16];
|
|
m_fir_tdata_q = tx_data_src_tdata[31-:16];
|
|
end
|
|
else if (cs == S_SEND_CHU_POS) begin
|
|
m_fir_tdata_i = chu_seq[15-:16];
|
|
m_fir_tdata_q = chu_seq[31-:16];
|
|
end
|
|
else if (cs == S_SEND_CHU_NEG) begin
|
|
m_fir_tdata_i = -chu_seq[15-:16];
|
|
m_fir_tdata_q = -chu_seq[31-:16];
|
|
end
|
|
else if (cs == S_TEST) begin
|
|
m_fir_tdata_i = {data_tx_test[3:0], 12'b0};
|
|
m_fir_tdata_q = {data_tx_test[7:4], 12'b0};
|
|
end
|
|
else begin
|
|
m_fir_tdata_i = 16'd0;
|
|
m_fir_tdata_q = 16'd0;
|
|
end
|
|
end
|
|
|
|
// count the block have been sent
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
cnt_blocks_send <= 4'd0;
|
|
end
|
|
else if (cs != S_SEND_PHASE1 && ns == S_SEND_PHASE1) begin
|
|
cnt_blocks_send <= cnt_blocks_send + 4'd1;
|
|
end
|
|
else if (cs == S_IDLE) begin
|
|
cnt_blocks_send <= 4'd0;
|
|
end
|
|
end
|
|
|
|
|
|
// S_WAIT_HOP && S_WAIT_GAP
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
cnt_wait <= 16'd0;
|
|
end
|
|
else if (cs == S_WAIT_HOP) begin
|
|
if (cnt_wait == hop_wait) begin
|
|
cnt_wait <= 1'd0;
|
|
end
|
|
else begin
|
|
cnt_wait <= cnt_wait + 16'd1;
|
|
end
|
|
end
|
|
else if (cs == S_WAIT_GAP) begin
|
|
if (cnt_wait == GAP_LEN - 1) begin
|
|
cnt_wait <= 1'd0;
|
|
end
|
|
else begin
|
|
cnt_wait <= cnt_wait + 16'd1;
|
|
end
|
|
end
|
|
else begin
|
|
cnt_wait <= 16'd0;
|
|
end
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
if (cs == S_SEND_PHASE1 && ns == S_IDLE) begin
|
|
send_over <= 1'd1;
|
|
end
|
|
else begin
|
|
send_over <= 1'd0;
|
|
end
|
|
end
|
|
|
|
// m seq addr control
|
|
always @(posedge clk) begin
|
|
mseqs_addr_d1 <= mseqs_addr;
|
|
mseqs_addr_d2 <= mseqs_addr_d1;
|
|
if (cs == S_IDLE) begin
|
|
mseqs_addr <= 1'd0;
|
|
end
|
|
else if (cs == S_SEND_FRAME_HEADER || cs == S_TEST) begin
|
|
if (fir_tvalid_in == 1'b1) begin
|
|
mseqs_addr <= mseqs_addr + 9'd1;
|
|
end
|
|
end
|
|
end
|
|
|
|
// chu seq addr control
|
|
always @(posedge clk) begin
|
|
if (cs == S_IDLE) begin
|
|
agc_addr <= 0;
|
|
end
|
|
else if (cs == S_SEND_AGC) begin
|
|
if (fir_tvalid_in == 1'b1) begin
|
|
agc_addr <= agc_addr + 1;
|
|
end
|
|
end
|
|
end
|
|
|
|
// chu seq addr control
|
|
always @(posedge clk) begin
|
|
if (ns != cs) begin
|
|
// chu_seq_addr <= 7'h7F - 7'h7; // 8 cp
|
|
chu_seq_addr <= CHU_SEQ_LEN - PREFIX_LEN; // 32 cp
|
|
end
|
|
else if (cs == S_SEND_CHU_POS || cs == S_SEND_AGC || cs == S_SEND_CHU_NEG) begin
|
|
if (fir_tvalid_in == 1'b1) begin
|
|
chu_seq_addr <= chu_seq_addr + 9'd1;
|
|
end
|
|
end
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
if (cs != ns) begin
|
|
cnt_chu_send <= 0;
|
|
end
|
|
else if (cs == S_SEND_CHU_POS || cs == S_SEND_CHU_NEG) begin
|
|
if (fir_tvalid_in) begin
|
|
cnt_chu_send <= cnt_chu_send + 1;
|
|
end
|
|
else begin
|
|
cnt_chu_send <= cnt_chu_send;
|
|
end
|
|
end
|
|
else begin
|
|
cnt_chu_send <= 0;
|
|
end
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
if (fir_tvalid_in) begin
|
|
addr_tx_test <= addr_tx_test + 1;
|
|
end
|
|
end
|
|
|
|
|
|
// ******** Inst ********
|
|
|
|
bram_agc_header u_bram_agc_header (
|
|
.clka (clk), // input wire clka
|
|
.addra(agc_addr), // input wire [13 : 0] addra
|
|
.douta(agc_data) // output wire [1 : 0] douta
|
|
);
|
|
|
|
bram_m_seqs_512 u_bram_m_seqs_512 (
|
|
.clka (clk),
|
|
.addra(mseqs_addr),
|
|
.douta(mseqs)
|
|
);
|
|
|
|
|
|
bram_chu_seq u_bram_chu_seq (
|
|
.clka (clk), // input wire clka
|
|
.addra(chu_seq_addr), // input wire [7 : 0] addra
|
|
.douta(chu_seq) // output wire [31 : 0] douta
|
|
);
|
|
|
|
|
|
bram_tx_test u_bram_tx_test (
|
|
.clka (clk), // input wire clka
|
|
.addra(addr_tx_test), // input wire [17 : 0] addra
|
|
.douta(data_tx_test) // output wire [31 : 0] douta
|
|
);
|
|
|
|
|
|
// fir i & q
|
|
fir_shape_interp16 u_fir_shape_interp16_i (
|
|
.aclk (clk), // input wire aclk
|
|
.s_axis_data_tvalid(fir_tvalid_in), // input wire s_axis_data_tvalid
|
|
.s_axis_data_tready(), // output wire s_axis_data_tready
|
|
.s_axis_data_tdata (m_fir_tdata_i), // input wire [15 : 0] s_axis_data_tdata
|
|
.m_axis_data_tvalid(), // output wire m_axis_data_tvalid
|
|
.m_axis_data_tdata (bb_wave_out_i_interp16) // output wire [31 : 0] m_axis_data_tdata
|
|
);
|
|
|
|
|
|
fir_shape_interp16 u_fir_shape_interp16_q (
|
|
.aclk (clk),
|
|
.s_axis_data_tvalid(fir_tvalid_in),
|
|
.s_axis_data_tready(),
|
|
.s_axis_data_tdata (m_fir_tdata_q),
|
|
.m_axis_data_tvalid(),
|
|
.m_axis_data_tdata (bb_wave_out_q_interp16)
|
|
);
|
|
|
|
// fir_shape_interp8 u_fir_shape_interp8_i (
|
|
// .aclk (clk),
|
|
// .s_axis_data_tvalid(fir_tvalid_in),
|
|
// .s_axis_data_tready(),
|
|
// .s_axis_data_tdata (m_fir_tdata_i),
|
|
// .m_axis_data_tvalid(),
|
|
// .m_axis_data_tdata (bb_wave_out_i_interp8)
|
|
// );
|
|
|
|
// fir_shape_interp8 u_fir_shape_interp8_q (
|
|
// .aclk (clk),
|
|
// .s_axis_data_tvalid(fir_tvalid_in),
|
|
// .s_axis_data_tready(),
|
|
// .s_axis_data_tdata (m_fir_tdata_q),
|
|
// .m_axis_data_tvalid(),
|
|
// .m_axis_data_tdata (bb_wave_out_q_interp8)
|
|
// );
|
|
|
|
// fir_shape_interp4 u_fir_shape_interp4_i (
|
|
// .aclk (clk),
|
|
// .s_axis_data_tvalid(fir_tvalid_in),
|
|
// .s_axis_data_tready(),
|
|
// .s_axis_data_tdata (m_fir_tdata_i),
|
|
// .m_axis_data_tvalid(),
|
|
// .m_axis_data_tdata (bb_wave_out_i_interp4)
|
|
// );
|
|
|
|
// fir_shape_interp4 u_fir_shape_interp4_q (
|
|
// .aclk (clk),
|
|
// .s_axis_data_tvalid(fir_tvalid_in),
|
|
// .s_axis_data_tready(),
|
|
// .s_axis_data_tdata (m_fir_tdata_q),
|
|
// .m_axis_data_tvalid(),
|
|
// .m_axis_data_tdata (bb_wave_out_q_interp4)
|
|
// );
|
|
|
|
|
|
|
|
// ******** Debug ********
|
|
|
|
// ila_transmitter u_ila_transmitter (
|
|
// .clk (clk), // input wire clk
|
|
// .probe0(cnt_sym_send), // input wire [15:0] probe0
|
|
// .probe1(cs), // input wire [3:0] probe1
|
|
// .probe2(ns), // input wire [3:0] probe2
|
|
// .probe3(send_data_ready), // input wire [0:0] probe3
|
|
// .probe4(send_start), // input wire [0:0] probe4
|
|
// .probe5(tx_data_src_tvalid) // input wire [0:0] probe5
|
|
// );
|
|
|
|
|
|
endmodule
|