Files
MM7020/hdl/enc_control.v
T

342 lines
13 KiB
Verilog

`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 >= 32 && 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), //! if the WIDTH or DATA_LEN parameter is changed, make sure the shift IP inside is also changed
.PREFIX_LEN(32)
) u_add_prefix (
.clk (clk),
.start (add_prefix_start),
.ready (add_prefix_in_ready),
.data_in ({data_add_prefix_in[0], data_add_prefix_in[1]}), // NOTE : reverse to adjust to IQmerge module
.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