`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