module Top(
    input SYM_CLK,
    input SW1,
    input KEY1,
    output out_pdm_sclk,
    output out_pcm_sync,
    output out_pcm_valid,
    output signed [23:0] out_pcm_data
);

//**********************************************************************
// --- Parameter
//**********************************************************************
	localparam NUM_CHN = 4;
    localparam MEM_DEPTH = 10240;
    localparam LATENCY = NUM_CHN+3;

//**********************************************************************
// --- Test Input signal
//**********************************************************************	
	wire clk, ce, rstn;
	
	wire in_pdm_valid;
	reg [LATENCY-1:0] pdm_valid_d;
	reg [NUM_CHN-1:0] in_pdm_data; 
	
	reg pdm_sclk_r0, pdm_sclk_r1;
	wire pdm_sclk_posedge;

//**********************************************************************
// --- Test Output signal
//**********************************************************************
	// wire out_pcm_valid;
	// wire out_pcm_sync;
    // wire out_pdm_sclk;
	// wire signed [DATA_WIDTH-1:0] out_pcm_data;
	
//**********************************************************************
// --- Inter Signal Declaration
//**********************************************************************	
	reg  onboard_en;
	
	reg [$clog2(NUM_CHN)-1:0] cnt_chn;
	reg [$clog2(NUM_CHN)-1:0] cnt_chn_d0;
	reg [$clog2(NUM_CHN)-1:0] cnt_chn_d1;
	
	reg [$clog2(MEM_DEPTH/NUM_CHN)-1:0] cnt_addr;
    reg [$clog2(MEM_DEPTH)-1:0] drom_addr;
	wire drom_out;
	
	reg pstart_dxn;
	reg restart;
	
//**********************************************************************	
// --- Initial Block
//**********************************************************************
	PDM2PCM_Top PDM2PCM_Top(
		.clk(clk), 
		.rstn(rstn & ~restart),
		.ce(ce),
	
		.out_pdm_sclk(out_pdm_sclk),
		.in_pdm_valid(in_pdm_valid),
		.in_pdm_data(in_pdm_data),
	
		.out_pcm_valid(out_pcm_valid),
		.out_pcm_sync(out_pcm_sync),
		.out_pcm_data(out_pcm_data)
	);

    assign clk = SYM_CLK;
    assign rstn = KEY1;
    assign ce = SW1;


//**********************************************************************
//----------read data from mem-----------
//**********************************************************************
// --- onboard_en
	always @(posedge clk or negedge rstn) begin
		if (!rstn)
			onboard_en <= 0;
		else if (ce)
			onboard_en <= 1;
	end

// --- pdm_sclk_posedge   
	always @(posedge clk or negedge rstn) begin
		if (!rstn) begin
			pdm_sclk_r0 <= 0;
			pdm_sclk_r1 <= 0;
		end
		else if(onboard_en) begin
			pdm_sclk_r0 <= out_pdm_sclk;
			pdm_sclk_r1 <= pdm_sclk_r0;
		end
	end
	assign pdm_sclk_posedge = pdm_sclk_r0 & ~(pdm_sclk_r1);

// --- restart
	always @(posedge clk or negedge rstn) begin
		if(!rstn) begin
			pstart_dxn <= 0;
		end
		else if(ce) begin
			if(cnt_addr == 1) pstart_dxn <= 1'b1;
		end
	end

	always @(posedge clk or negedge rstn) begin
		if(!rstn) restart <= 1'b0;
		else if(onboard_en & pstart_dxn) begin
			if(drom_addr == 0) restart <= 1'b1;
			else restart <= 1'b0;
		end
	end


// --- cnt_addr
	always @(posedge clk or negedge rstn) begin
		if(!rstn) begin
			cnt_addr <= MEM_DEPTH/NUM_CHN-1;
		end
		else if(onboard_en) begin
			if(pdm_sclk_posedge && cnt_addr == MEM_DEPTH/NUM_CHN-1)   cnt_addr <= 0;
			else if(pdm_sclk_posedge) cnt_addr <= cnt_addr + 1;
		end
	end

// --- cnt_chn
	always @(posedge clk or negedge rstn) begin
		if(!rstn) begin
			cnt_chn <= NUM_CHN-1;
		end
		else if(onboard_en) begin
			if(pdm_sclk_posedge && cnt_chn == NUM_CHN-1)  cnt_chn <= 0;
            else if(cnt_chn == NUM_CHN-1)  cnt_chn <= cnt_chn;
			else cnt_chn <= cnt_chn + 1;
		end
	end

// --- drom_addr	
	always @(posedge clk or negedge rstn) begin
		if(!rstn) drom_addr <= MEM_DEPTH-1;
	`ifdef NUM_CHN_EQ_1	
		else if(onboard_en) drom_addr <= cnt_addr;
	`else
		else if(onboard_en) drom_addr <= cnt_addr*NUM_CHN + cnt_chn;
	`endif
	end
	
// --- Data_Rom
	Data_ROM data_rom(
        .dout(drom_out), //output [0:0] dout
        .clk(clk), //input clk
        .oce(onboard_en), //input oce
        .ce(onboard_en), //input ce
        .reset(~rstn), //input reset
        .wre(1'b0), //input wre
        .ad(drom_addr) //input [13:0] ad
    );

// cnt_chn_d	
	always @(posedge clk or negedge rstn) begin
		if(!rstn) begin 
			cnt_chn_d0 <= 0;
			cnt_chn_d1 <= 0;
		end
		else if(onboard_en) begin
			cnt_chn_d0 <= cnt_chn;
			cnt_chn_d1 <= cnt_chn_d0;
		end
	end
// --- in_pdm_data
	always @(posedge clk or negedge rstn) begin
		if(!rstn) in_pdm_data <= 0;
		else if(onboard_en) begin
			in_pdm_data[cnt_chn_d1] <= drom_out;
		end
	end

// --- in_pdm_valid
	always @(posedge clk or negedge rstn) begin
		if(!rstn) pdm_valid_d <= 0;
		else if(onboard_en) pdm_valid_d <= {pdm_valid_d[LATENCY-2:0], pdm_sclk_posedge};
	end
	
	assign in_pdm_valid = pdm_valid_d[LATENCY-1];
	



endmodule