Files
MM7020/hdl/Transmitter.v

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