`timescale 1ns / 1ns // ******************************************************* // * ███████╗ ██████╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗ * // * ╚══███╔╝██╔═══██╗██╔══██╗██╔═══██╗██╔════╝ ██║ ██║ * // * ███╔╝ ██║ ██║██████╔╝██║ ██║██║ ███╗███████║ * // * ███╔╝ ██║ ██║██╔══██╗██║ ██║██║ ██║██╔══██║ * // * ███████╗╚██████╔╝██║ ██║╚██████╔╝╚██████╔╝██║ ██║ * // * ╚══════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ * // ******************************************************* // * this module get data from the ps ( a axis-fifo in fact) // * and then use the ldpc algorithm to encode the data, which // * is 16 bit parallel, then it dose a width convert to // * 2 bit (i and q) , add a prefix which is 8 sym len. finally, // * send the data with prefix to a fifo (2 bit width, ditributed ram), // * waiting the transmitter to fetch // * // * later update (2024/5/14): // * we find the 16bit parallel cost too much resource, so we change it // * to 1bit serial module, // * 该模块首先将输入的数据32bit数据进行位宽转换为1bit数据,输入到ldpc模块中进行编码 // * 然后将ldpc模块通过fifo进行位宽转换成2bit数据(Q,I),然后添加循环前缀(8个符号) // * 送入到fifo_enc_out中,并结束。 // * // * Q : 何时开始编码? // * A : 前端有数据下发,且该模块是输出fifo模块中数据不足(<200syms)才进行编码。 module enc_control #( parameter ENC_IN_LEN = 1024, parameter ENC_OUT_LEN = 2048, parameter INPUT_DATA_WIDTH = 32 ) ( input clk, input rst, //from ps axis-fifo input s_axis_fifo_tvalid, output reg s_axis_fifo_tready, input [INPUT_DATA_WIDTH - 1:0] s_axis_fifo_tdata, input [ 31:0] data_src_count, // fifo signal input wire fifo_enc_out_rd_clk, input wire fifo_enc_out_rd_en, output wire [ 31:0] fifo_enc_out_dout_map, output wire fifo_enc_out_empty ); // ******** Wire & Reg ******** localparam CNT_IN_MAX = ENC_IN_LEN / INPUT_DATA_WIDTH; localparam CNT_IN_WIDTH = $clog2(CNT_IN_MAX); localparam CNT_OUT_MAX = ENC_OUT_LEN; localparam CNT_OUT_WIDTH = $clog2(CNT_OUT_MAX); // 多留1bit // status localparam [3:0] S_IDLE = 4'd0; localparam [3:0] S_START = 4'd1; localparam [3:0] S_WAIT_LDPC_OUT = 4'd2; localparam [3:0] S_WAIT_ADD_PREFIX_DONE = 4'd3; reg [ 3:0] cs; reg [ 3:0] ns; // input data width convert reg wc_data_in_valid; wire wc_data_in_ready; wire [ 31:0] wc_data_in; wire wc_data_out_valid; wire wc_data_out; // ldpc io signal reg ldpc_in_start; reg ldpc_in_valid; wire ldpc_out_start; wire ldpc_out_valid; wire ldpc_dout; // ldpc io cnt reg [ CNT_IN_WIDTH : 0] cnt_in; // 多留1bit reg [CNT_OUT_WIDTH : 0] cnt_out; // 多留1bit // map wire [ 1:0] fifo_enc_out_dout; wire [ 15:0] fifo_enc_out_dout_i; wire [ 15:0] fifo_enc_out_dout_q; wire fifo_enc_out_almost_empty; wire fifo_enc_out_prog_empty_1x; // 20 sym wire fifo_enc_out_prog_empty; // 20 sym // control the fifo width convert read channel wire fifo_wc_prog_full; reg fifo_wc_prog_full_d1; wire fifo_wc_empty; reg add_prefix_start; // signal for add_prefix reg [ 2:0] cnt_add_prefix_in; wire add_prefix_in_ready; wire [ 1:0] data_add_prefix_in; wire data_add_prefix_in_ready; wire [ 1:0] data_add_prefix_out; wire data_add_prefix_out_valid; // ******** Assingment ******** assign fifo_enc_out_dout_i = (fifo_enc_out_dout[0] == 1'b0) ? 16'h7FFF : 16'h8001; assign fifo_enc_out_dout_q = (fifo_enc_out_dout[1] == 1'b0) ? 16'h7FFF : 16'h8001; assign fifo_enc_out_dout_map = {fifo_enc_out_dout_q, fifo_enc_out_dout_i}; assign wc_data_in = s_axis_fifo_tdata; // ******** Logic Block ******** always @(posedge clk) begin if (rst == 1'b1) begin cs <= S_IDLE; end else begin cs <= ns; end end // fsm always @(*) begin // NOTE: S_IDLE --> START (width convert --> encoding module) --> wait output done --> IDLE case (cs) S_IDLE: begin // ! attention // if source is valid which means there are data waiting for encoding // and the pre-stage fifo counts not equal 0 // and the width convert fifo is empty // and the finally stage fifo is almost empty // TODO:check the conditions, done 2024年5月27日 if (s_axis_fifo_tvalid && data_src_count != 0 && fifo_enc_out_prog_empty && ~data_add_prefix_in_ready && ~data_add_prefix_out_valid) begin ns = S_START; end else begin ns = S_IDLE; end end S_START: begin ns = S_WAIT_LDPC_OUT; end S_WAIT_LDPC_OUT: begin if (cnt_out == CNT_OUT_MAX) begin ns = S_WAIT_ADD_PREFIX_DONE; end else begin ns = S_WAIT_LDPC_OUT; end end S_WAIT_ADD_PREFIX_DONE: begin if (fifo_wc_empty && add_prefix_in_ready) begin ns = S_IDLE; end else begin ns = S_WAIT_ADD_PREFIX_DONE; end end default: begin ns = S_IDLE; end endcase end always @(posedge clk) begin if (rst) begin wc_data_in_valid <= 0; end else if (ns == S_START || cnt_in < CNT_IN_MAX && cs != S_IDLE) begin wc_data_in_valid <= s_axis_fifo_tvalid; end else begin wc_data_in_valid <= 0; end end always @(*) begin if (rst) begin s_axis_fifo_tready = 0; end else begin if (cs != S_IDLE && cnt_in < CNT_IN_MAX) begin s_axis_fifo_tready = wc_data_in_ready; end else begin s_axis_fifo_tready = 0; end end end always @(*) begin ldpc_in_start = (cs == S_START); ldpc_in_valid = wc_data_out_valid; end always @(posedge clk) begin if (cs == S_IDLE) begin cnt_in <= 0; end else if (wc_data_in_ready && wc_data_in_valid) begin cnt_in <= cnt_in + 1; end end always @(posedge clk) begin if (ldpc_out_start || cnt_out > 0 && cnt_out <= CNT_OUT_MAX) begin cnt_out <= cnt_out + 1; end else begin cnt_out <= 0; end end // get the rising edge always @(posedge clk) begin fifo_wc_prog_full_d1 <= fifo_wc_prog_full; end // shit code, no modify timing is in a mess always @(posedge clk) begin if (rst) begin cnt_add_prefix_in <= 0; end else if (fifo_wc_prog_full & ~fifo_wc_prog_full_d1) begin cnt_add_prefix_in <= cnt_add_prefix_in + 1; end else if (add_prefix_start) begin if (cnt_add_prefix_in < 4) begin cnt_add_prefix_in <= cnt_add_prefix_in + 1; end else begin cnt_add_prefix_in <= 0; end end end always @(posedge clk) begin if (rst) begin add_prefix_start <= 0; end else if (fifo_wc_prog_full & ~fifo_wc_prog_full_d1 || cnt_add_prefix_in > 0 && add_prefix_in_ready && ~add_prefix_start) begin add_prefix_start <= 1'b1; end else begin add_prefix_start <= 1'b0; end end // ******** Inst ******** width_convert #( .INPUT_WIDTH (32), .OUTPUT_WIDTH(1) ) u_width_convert ( .clk (clk), .rst (rst), .data_in_valid (wc_data_in_valid), .data_in_ready (wc_data_in_ready), .data_in (wc_data_in), .data_out_valid(wc_data_out_valid), .data_out (wc_data_out) ); // encoding module CCSDS_LDPC_ENC_R12 u_CCSDS_LDPC_ENC_R12 ( .clk (clk), .rst (rst), .Encoder_SyncIn (ldpc_in_start), .Encoder_Nd (ldpc_in_valid), .Encoder_Din (wc_data_out), .Encode_Dout (ldpc_dout), .Encode_Sync_Dout(ldpc_out_start), .Encode_Rdy (ldpc_out_valid) ); fifo_width_convert_1_2 u_fifo_width_convert_1_2 ( .clk (clk), // input wire clk .srst (rst), // input wire srst .din (ldpc_dout), // input wire [0 : 0] din .wr_en (ldpc_out_valid), // input wire wr_en .rd_en (data_add_prefix_in_ready), // input wire rd_en .dout (data_add_prefix_in), // output wire [1 : 0] dout .full (), // output wire full .empty (fifo_wc_empty), // output wire empty .prog_full(fifo_wc_prog_full) ); add_prefix #( .WIDTH (2), // ! if this parameter is changed, make sure the shift IP inside is also changed .DATA_LEN (256), .PREFIX_LEN(8) ) u_add_prefix ( .clk (clk), .start (add_prefix_start), .ready (add_prefix_in_ready), .data_in (data_add_prefix_in), .data_in_ready (data_add_prefix_in_ready), .data_out (data_add_prefix_out), .data_out_valid(data_add_prefix_out_valid) ); fifo_enc_out u_fifo_enc_out ( .rst (rst), // input wire rst .wr_clk (clk), // input wire wr_clk .rd_clk (fifo_enc_out_rd_clk), // input wire rd_clk .din (data_add_prefix_out), // input wire [1 : 0] din .wr_en (data_add_prefix_out_valid), // input wire wr_en .rd_en (fifo_enc_out_rd_en), // input wire rd_en .dout (fifo_enc_out_dout), // output wire [1 : 0] dout .full (), // output wire full .empty (fifo_enc_out_empty), // output wire empty .almost_empty(fifo_enc_out_almost_empty), // output wire almost_empty .prog_empty (fifo_enc_out_prog_empty_1x) // output wire prog_empty ); xpm_cdc_single #( .DEST_SYNC_FF (4), // DECIMAL; range: 2-10 .INIT_SYNC_FF (0), // DECIMAL; 0=disable simulation init values, 1=enable simulation init values .SIM_ASSERT_CHK(0), // DECIMAL; 0=disable simulation messages, 1=enable simulation messages .SRC_INPUT_REG (1) // DECIMAL; 0=do not register input, 1=register input ) xpm_cdc_single_inst ( .dest_out(fifo_enc_out_prog_empty), // 1-bit output: src_in synchronized to the destination clock domain. This output is registered. .dest_clk(clk), // 1-bit input: Clock signal for the destination clock domain. .src_clk (fifo_enc_out_rd_clk), // 1-bit input: optional; required when SRC_INPUT_REG = 1 .src_in (fifo_enc_out_prog_empty_1x) // 1-bit input: Input signal to be synchronized to dest_clk domain. ); // ******** Debug ******** endmodule