342 lines
13 KiB
Verilog
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
|