//+FHDR--------------------------------------------------------------------------------------------------------
//  Company: 
//-----------------------------------------------------------------------------------------------------------------
//  File Name             :    awg_ctrl.v
//  Department            :    
//  Author                :    hdzhang
//  Author's Tel          :     
//-----------------------------------------------------------------------------------------------------------------
//  Relese History
//  Version     Date            Author          Description
//  0.1         2026-02-28      hdzhang         fifo-cmd controlled waveform output
//-----------------------------------------------------------------------------------------------------------------
//  Keywords            :       
//
//-----------------------------------------------------------------------------------------------------------------
//  Parameter
//
//-----------------------------------------------------------------------------------------------------------------
//  Purpose                 :
//                      
//-----------------------------------------------------------------------------------------------------------------
//  Target Device:        
//  Tool versions:        
//-----------------------------------------------------------------------------------------------------------------
//  Reuse Issues
//  Reset Strategy: 
//  Clock Domains: 
//  Critical Timing:
//  Asynchronous I/F:
//  Synthesizable (y/n): 
//  Other:
//-FHDR--------------------------------------------------------------------------------------------------------

module awg_ctrl (
    //system port
     input          clk                      // System Main Clock
    ,input          rst_n                    // Spi Reset active low
    //sync signal
    ,input          start
    //cmd fifo read signal
    ,output         cmd_fifo_rd_en
    ,input  [31 :0] cmd_fifo_data
    ,input          cmd_fifo_empty
    //wave sram read signals
    ,output         sram_rd_en
    ,output [12 :0] sram_rd_addr
    ,input  [511:0] sram_rd_data
    //output to dem module
    ,output [511:0] wave_data_out
    ,output         wave_valid_out
    //state submit
    ,output [2  :0] status
    ,output         wave_busy
);

localparam    IDLE = 3'b0, CMD = 3'd1, WAVE = 3'd2, HOLD = 3'd3;
wire [2  : 0] state_c;
wire          wave_cnt_add, wave_cnt_end;
wire [4  : 0] wave_cnt_c;
wire          hold_cnt_add, hold_cnt_end;
wire [30 : 0] hold_cnt_c;

//wire          cmd_fifo_has_empty = cmd_fifo_empty && cmd_fifo_rd_en;
// ------------------------------------------------------
// -- state machine
// ------------------------------------------------------
//jump conditions
wire          ilde2cmd     = (state_c == IDLE) && start;
wire          cmd2wave     = (state_c == CMD ) && ~cmd_fifo_data[31];
wire          cmd2hold     = (state_c == CMD ) &&  cmd_fifo_data[31];
wire          wave2hold    = (state_c == WAVE) &&  wave_cnt_end &&  cmd_fifo_data[31] && ~cmd_fifo_empty;
wire          wave2idle    = (state_c == WAVE) &&  wave_cnt_end &&  cmd_fifo_empty;
wire          hold2wave    = (state_c == HOLD) &&  hold_cnt_end && ~cmd_fifo_data[31] && ~cmd_fifo_empty;
wire          hold2idle    = (state_c == HOLD) &&  hold_cnt_end &&  cmd_fifo_empty;
//state_n
wire [2  : 0] state_n = ((state_c == IDLE) && ilde2cmd  ) ? CMD  :
                        ((state_c == CMD ) && cmd2wave  ) ? WAVE :
                        ((state_c == CMD ) && cmd2hold  ) ? HOLD :
                        ((state_c == WAVE) && wave2hold ) ? HOLD :
                        ((state_c == WAVE) && wave2idle ) ? IDLE :
                        ((state_c == HOLD) && hold2wave ) ? WAVE :
                        ((state_c == HOLD) && hold2idle ) ? IDLE :
                        state_c ;
//state_c
sirv_gnrl_dffr #(3) state_c_dffr (state_n, state_c, clk, rst_n);

// ------------------------------------------------------
// -- command decode
// ------------------------------------------------------
assign        cmd_fifo_rd_en = ((state_c == CMD) || wave_cnt_end || hold_cnt_end) && ~cmd_fifo_empty;
wire [4  : 0] cycle_num;
wire [12 : 0] base_addr;
wire [12 : 0] wave_leng;
wire [30 : 0] hold_leng;
sirv_gnrl_dfflr #( 5) cycle_num_dfflr (cmd_fifo_rd_en && ~cmd_fifo_data[31], cmd_fifo_data[30:26], cycle_num, clk, rst_n);
sirv_gnrl_dfflr #(13) base_addr_dfflr (cmd_fifo_rd_en && ~cmd_fifo_data[31], cmd_fifo_data[25:13], base_addr, clk, rst_n);
sirv_gnrl_dfflr #(13) wave_leng_dfflr (cmd_fifo_rd_en && ~cmd_fifo_data[31], cmd_fifo_data[12: 0], wave_leng, clk, rst_n);
sirv_gnrl_dfflr #(31) hold_leng_dfflr (cmd_fifo_rd_en &&  cmd_fifo_data[31], cmd_fifo_data[30: 0], hold_leng, clk, rst_n);

// ------------------------------------------------------
// -- wave memory address count
// ------------------------------------------------------
wire [12 : 0] addr_cnt_c;  
wire          addr_cnt_add  =   (state_c == WAVE);
wire          addr_cnt_end  =   addr_cnt_add && (addr_cnt_c == wave_leng - 1);
wire [12 : 0] addr_cnt_n    =   addr_cnt_end ?  13'h0             :
                                addr_cnt_add ?  addr_cnt_c + 1'b1 :
                                                addr_cnt_c        ;
sirv_gnrl_dffr #(13) addr_cnt_c_dffr (addr_cnt_n, addr_cnt_c, clk, rst_n);

// ------------------------------------------------------
// -- wave repeat count
// ------------------------------------------------------ 
assign        wave_cnt_add  =   addr_cnt_end;
assign        wave_cnt_end  =   wave_cnt_add && (wave_cnt_c == cycle_num - 1) && (cycle_num != 5'd0);
wire [4  : 0] wave_cnt_n    =   wave_cnt_end ?  5'h0              :
                                wave_cnt_add ?  wave_cnt_c + 1'b1 :
                                                wave_cnt_c        ;
sirv_gnrl_dffr #( 5) wave_cnt_c_dffr (wave_cnt_n, wave_cnt_c, clk, rst_n);

// ------------------------------------------------------
// -- hold length count
// ------------------------------------------------------ 
assign        hold_cnt_add  =   (state_c == HOLD);
assign        hold_cnt_end  =   hold_cnt_add && (hold_cnt_c == hold_leng - 1);
wire [30 : 0] hold_cnt_n    =   hold_cnt_end ?  5'h0              :
                                hold_cnt_add ?  hold_cnt_c + 1'b1 :
                                                hold_cnt_c        ;
sirv_gnrl_dffr #(31) hold_cnt_c_dffr (hold_cnt_n, hold_cnt_c, clk, rst_n);

// ------------------------------------------------------
// -- read wave SRAM
// ------------------------------------------------------ 
sirv_gnrl_dffr #(1) sram_rd_en_dffr ((state_c == WAVE), sram_rd_en, clk, rst_n);
sirv_gnrl_dffr #(13) sram_rd_addr_dffr (base_addr + addr_cnt_c, sram_rd_addr, clk, rst_n);

wire          last_sram_rd_en, last_wave_data_vld;
wire [7  : 0] last_rddata;
sirv_gnrl_dffr #(1) last_sram_rd_en_dffr (wave_cnt_end, last_sram_rd_en, clk, rst_n);
sirv_gnrl_dffr #(1) last_wave_data_dffr (last_sram_rd_en, last_wave_data_vld, clk, rst_n);
sirv_gnrl_dfflr #(8) last_rddata_dfflr (last_wave_data_vld, sram_rd_data[511:504], last_rddata, clk, rst_n);

wire          wave_vld, hold_vld_n, hold_vld;
sirv_gnrl_dffr #(1) wave_vld_dffr (sram_rd_en, wave_vld, clk, rst_n);
sirv_gnrl_dffr #(1) hold_vld_n_dffr ((state_c == HOLD), hold_vld_n, clk, rst_n);
sirv_gnrl_dffr #(1) hold_vld_dffr (hold_vld_n, hold_vld, clk, rst_n);

wire [511: 0] wave_data  =  wave_vld ?  sram_rd_data      :
                            hold_vld ?  {64{last_rddata}} :
                                        512'd0            ;

sirv_gnrl_dffr #(1) wave_valid_dffr (wave_vld | hold_vld, wave_valid_out, clk, rst_n);
sirv_gnrl_dfflr #(512) wave_data_dfflr (wave_vld | hold_vld | wave_valid_out, wave_data, wave_data_out, clk, rst_n);

//status
assign status = state_c;
assign wave_busy = (state_c == WAVE) || (state_c == HOLD);
endmodule
