//FILE_HEADER-------------------------------------------------------
//FILE_NAME       : readout_awg_rm.sv
//DEPARTEMENT     : QuantumCTek-ASIC
//AUTHOR          : Yunzhuo Zhang
//TIME            : 2025.4.10
//*******************************************************************
//DESCRIPTION     : awg reference model define
//*******************************************************************
//END_HEADER*********************************************************


`ifndef  READOUT_AWG_RM
`define READOUT_AWG_RM

`include "../testbench/refm/mcu_cw_item.sv"
`include "../testbench/refm/nco_dpi/codegen/dll/nco_model/nco_dpi_pkg.sv"
`include "../testbench/refm/hilbert_dpi/codegen/dll/hilbert_fir/hilbert_fir_dpi_pkg.sv"

import nco_dpi_pkg::*;
import hilbert_fir_dpi_pkg::*;

class readout_awg_rm extends uvm_component;
	`uvm_component_utils(readout_awg_rm);
	virtual rm_if rm_if; 	//sync

	uvm_analysis_port #(EZQ_readout_dac_item)  dac_rm2scb_port;		
	uvm_blocking_get_port #(mcu_cw_item)  mcu_get_port; 					 
	
	bit [31:0]	mcu_timer	;
	bit [31:0]	mcu_counter 	;
	bit [31:0]	loc_state	;
	bit [31:0]	glb_state	;
	bit [31:0]	feed_data	;	
	bit [31:0]	wave_ctrl	;
	bit [31:0]	amplitude	;
	bit [31:0]	frequency	;
	bit [31:0]	phase	    	;
	bit [31:0]	command	    	;
	bit [31:0]	func_ctrl	;
	bit [31:0]	pump_ctrl	;
	bit [31:0]	mark_ctrl	;
	
	bit [31:0]	cw_data		;
	bit 		cw_valid	;
	mcu_cw_item cw_queue[$]	;

	bit [31:0]	clock_cycle	;
	bit [31:0]	awg_clock_cycle	;
	bit [15:0]	env_len			;





    bit [31:0] 	ram_data[bit[31:0]];
	bit [31:0]	wr_data		;
	bit [31:0]	wr_addr		;

	bit [31:0] dac_send_cnt	;

	bit [15:0]data_out_0[$];
	bit [15:0]data_out_1[$];
	bit [15:0]data_out_2[$];
	bit [15:0]data_out_3[$];
	bit [15:0]data_out_4[$];
	bit [15:0]data_out_5[$];
	bit [15:0]data_out_6[$];
	bit [15:0]data_out_7[$];
	bit [15:0]data_outb_0[$];
	bit [15:0]data_outb_1[$];
	bit [15:0]data_outb_2[$];
	bit [15:0]data_outb_3[$];
	bit [15:0]data_outb_4[$];
	bit [15:0]data_outb_5[$];
	bit [15:0]data_outb_6[$];
	bit [15:0]data_outb_7[$];


		
    extern function new(string name,uvm_component parent);
    extern function void build_phase(uvm_phase phase);
    extern virtual task run_phase(uvm_phase phase);

	extern task get_mcu_cw_item();
	extern task get_spi_item();	
	extern task get_config_data();	
	extern task send_dac_item();	
	extern task awg_exe();		
	extern task if_pump_mark();		
	extern task hilbert_fir(
		input  bit signed [15:0] hilbert_in[$],
		input  bit 		  [15:0] data_size,
		output bit signed [15:0] hilbert_out[$]
	);	
endclass

function readout_awg_rm::new(string name,uvm_component parent);
	super.new(name,parent);
endfunction : new

function void readout_awg_rm::build_phase(uvm_phase phase);
    super.build_phase(phase);
    if(!uvm_config_db#(virtual rm_if)::get(this,"","rm_if",rm_if))
	    `uvm_fatal("CFGERR",{"virtual interface must be set for: ",get_full_name(),".vif"});
    mcu_get_port = new("spi_get_port",this);
    dac_rm2scb_port = new("dac_rm2scb_port",this);
endfunction


task readout_awg_rm::get_mcu_cw_item();
	mcu_cw_item mcu_cw_item;
    forever begin
        mcu_get_port.get(mcu_cw_item);
		cw_data		= mcu_cw_item.cw_data;
		cw_valid	= mcu_cw_item.cw_valid;
        `uvm_info(get_type_name(),$sformatf("awg_mcu_cw_data = %0h,awg_mcu_cycle = %0h,awg_cw_valid = %h",cw_data,mcu_cw_item.clock_cycle,cw_valid),UVM_LOW)

		if(cw_valid)begin
			clock_cycle = mcu_cw_item.clock_cycle;
			cw_queue.push_back(mcu_cw_item);
        	`uvm_info(get_type_name(),$sformatf("cw_queue_size = %0h",cw_queue.size()),UVM_MEDIUM)
		end		
    end	
endtask

task readout_awg_rm::get_spi_item();
    forever begin
		@(wr_data or wr_addr)
			ram_data[wr_addr] = wr_data;
        `uvm_info(get_type_name(),$sformatf("wr_addr = %0h,wr_data = %0h",wr_addr,wr_data),UVM_LOW)
    end	
endtask


task readout_awg_rm::get_config_data();
    forever begin
       @(posedge `CLK);
		if(ram_data.exists(`AWG_MCU_TIMER))begin
			mcu_timer = ram_data[`AWG_MCU_TIMER];
		end
		if(ram_data.exists(`AWG_MCU_COUNTER))begin
			mcu_counter = ram_data[`AWG_MCU_COUNTER];
		end
		if(ram_data.exists(`AWG_LOC_STATE))begin
			loc_state = ram_data[`AWG_LOC_STATE];
		end
		if(ram_data.exists(`AWG_GLB_STATE))begin
			glb_state = ram_data[`AWG_GLB_STATE];
		end
/*
		if(ram_data.exists(`AWG_FEED_DATA))begin
			feed_data = ram_data[`AWG_FEED_DATA];
		end
*/
		if(ram_data.exists(`WAVE_CTRL))begin
			wave_ctrl = ram_data[`WAVE_CTRL];
		end
		if(ram_data.exists(`AMPLITUDE))begin
			amplitude = ram_data[`AMPLITUDE];
		end
		if(ram_data.exists(`FREQUENCY))begin
			frequency = ram_data[`FREQUENCY];
		end
		if(ram_data.exists(`PHASE))begin
			phase 	  = ram_data[`PHASE];
		end
		if(ram_data.exists(`AWG_COMMAND))begin
			command = ram_data[`AWG_COMMAND];
		end
		if(ram_data.exists(`AWG_FUNC_CTRL))begin
			func_ctrl = ram_data[`AWG_FUNC_CTRL];
		end
		if(ram_data.exists(`PUMP_CTRL))begin
			pump_ctrl = ram_data[`PUMP_CTRL];
		end 
		else begin
			pump_ctrl = 32'h10010;
		end
		if(ram_data.exists(`MARK_CTRL))begin
			mark_ctrl = ram_data[`MARK_CTRL];
		end
		else begin
			mark_ctrl = 32'h10010;
		end

    end	
endtask	

task readout_awg_rm::send_dac_item();
	EZQ_readout_dac_item dac_item_pkt;
    forever begin
		if(data_out_0.size()>`DAC_MON_CYCLE)begin
			dac_item_pkt = new();

 			dac_item_pkt.data_out0  = data_out_0[0+: `DAC_MON_CYCLE];
			dac_item_pkt.data_out1  = data_out_1[0+: `DAC_MON_CYCLE];
  			dac_item_pkt.data_out2  = data_out_2[0+: `DAC_MON_CYCLE];
			dac_item_pkt.data_out3  = data_out_3[0+: `DAC_MON_CYCLE];
 			dac_item_pkt.data_out4  = data_out_4[0+: `DAC_MON_CYCLE];
			dac_item_pkt.data_out5  = data_out_5[0+: `DAC_MON_CYCLE]; 		
			dac_item_pkt.data_out6  = data_out_6[0+: `DAC_MON_CYCLE]; 		
			dac_item_pkt.data_out7  = data_out_7[0+: `DAC_MON_CYCLE]; 		
			dac_item_pkt.data_outb0 = data_outb_0[0+: `DAC_MON_CYCLE];  		
			dac_item_pkt.data_outb1 = data_outb_1[0+: `DAC_MON_CYCLE];
			dac_item_pkt.data_outb2 = data_outb_2[0+: `DAC_MON_CYCLE];
			dac_item_pkt.data_outb3 = data_outb_3[0+: `DAC_MON_CYCLE];
			dac_item_pkt.data_outb4 = data_outb_4[0+: `DAC_MON_CYCLE];
			dac_item_pkt.data_outb5 = data_outb_5[0+: `DAC_MON_CYCLE]; 
			dac_item_pkt.data_outb6 = data_outb_6[0+: `DAC_MON_CYCLE]; 
			dac_item_pkt.data_outb7 = data_outb_7[0+: `DAC_MON_CYCLE]; 
//			dac_item_pkt.delay_cycle = awg_clock_cycle;

			dac_rm2scb_port.write(dac_item_pkt);

 	       `uvm_info(get_type_name(),$sformatf("dac_send_cnt  = %0h",dac_send_cnt),UVM_LOW)

 	       `uvm_info(get_type_name(),$sformatf("data_out_0[0+: `DAC_MON_CYCLE] = %0p",data_out_0[0+: `DAC_MON_CYCLE]),UVM_LOW)
/*
	       `uvm_info(get_type_name(),$sformatf("data_out_1 = %0p",data_out_1),UVM_LOW)
	       `uvm_info(get_type_name(),$sformatf("data_out_2 = %0p",data_out_2),UVM_LOW)
	       `uvm_info(get_type_name(),$sformatf("data_out_3 = %0p",data_out_3),UVM_LOW)
	       `uvm_info(get_type_name(),$sformatf("data_out_4 = %0p",data_out_4),UVM_LOW)
	       `uvm_info(get_type_name(),$sformatf("data_out_5 = %0p",data_out_5),UVM_LOW)
	       `uvm_info(get_type_name(),$sformatf("data_out_6 = %0p",data_out_6),UVM_LOW)
	       `uvm_info(get_type_name(),$sformatf("data_out_7 = %0p",data_out_7),UVM_LOW)
	       `uvm_info(get_type_name(),$sformatf("data_outb_0 = %0p",data_outb_0),UVM_LOW)
	       `uvm_info(get_type_name(),$sformatf("data_outb_1 = %0p",data_outb_1),UVM_LOW)
	       `uvm_info(get_type_name(),$sformatf("data_outb_2 = %0p",data_outb_2),UVM_LOW)
	       `uvm_info(get_type_name(),$sformatf("data_outb_3 = %0p",data_outb_3),UVM_LOW)
	       `uvm_info(get_type_name(),$sformatf("data_outb_4 = %0p",data_outb_4),UVM_LOW)
	       `uvm_info(get_type_name(),$sformatf("data_outb_5 = %0p",data_outb_5),UVM_LOW)
	       `uvm_info(get_type_name(),$sformatf("data_outb_6 = %0p",data_outb_6),UVM_LOW	       
		   `uvm_info(get_type_name(),$sformatf("data_outb_7 = %0p",data_outb_7),UVM_LOW)
	       `uvm_info(get_type_name(),$sformatf("data_outb_7 = %0p",data_outb_7),UVM_LOW)
*/
			data_out_0 	= 	data_out_0[`DAC_MON_CYCLE : $];
			data_out_1 	= 	data_out_1[`DAC_MON_CYCLE : $];
			data_out_2 	= 	data_out_2[`DAC_MON_CYCLE : $];
			data_out_3 	= 	data_out_3[`DAC_MON_CYCLE : $];
			data_out_4 	= 	data_out_4[`DAC_MON_CYCLE : $];
			data_out_5 	= 	data_out_5[`DAC_MON_CYCLE : $];  
			data_out_6 	= 	data_out_6[`DAC_MON_CYCLE : $];  
			data_out_7 	= 	data_out_7[`DAC_MON_CYCLE : $];  
			data_outb_0	= 	data_outb_0[`DAC_MON_CYCLE : $];
			data_outb_1	=	data_outb_1[`DAC_MON_CYCLE : $];
			data_outb_2	=	data_outb_2[`DAC_MON_CYCLE : $];
			data_outb_3	=	data_outb_3[`DAC_MON_CYCLE : $];
			data_outb_4	=	data_outb_4[`DAC_MON_CYCLE : $];
			data_outb_5	=	data_outb_5[`DAC_MON_CYCLE : $]; 
			data_outb_6	=	data_outb_6[`DAC_MON_CYCLE : $]; 
			data_outb_7	=	data_outb_7[`DAC_MON_CYCLE : $]; 

			dac_send_cnt++;
			end
		@(posedge `CLK);
     end	

endtask

task readout_awg_rm::awg_exe();
//fid
  	chandle       	objhandle = null	;
 	chandle       	OBJhandle = null	;
	bit [31:0] 		zeros_len;

//get wave_idx & wave
	bit	[5 :0]		wave_id			;
	bit	[24:0]		env_map_addr	;
	bit	[31:0]		env_idx			;
	bit	[24:0]		env_addr		;
	bit	[24:0]		env_addr_1		;
	bit	[24:0]		env_addr_2		;
	bit	[24:0]		env_addr_3		;


	bit	[`NUM_WAY*`DATA_WIDTH-1 :0]	wave_out		;
	bit	[31:0]		wave_out_0	;
	bit	[31:0]		wave_out_1	;
	bit	[31:0]		wave_out_2	;
	bit	[31:0]		wave_out_3	;

	bit	[127:0]		wave_out_queue[$]	;
	int				k			;
	
//wave_mod output signal
	bit	[1 :0] 		mod_mode		;
	bit	 			loc_rst_n		;
	bit	 			hilbert_en		;
	bit	 			iq_mod_en		;
	bit				clr_en			;
	bit				mix_en			;
	int				j			;

	bit [47:0] 		frequency_48;
	real			nco_acc_out			;
	real			nco_acc_in			;

	bit	signed[15:0]	nco_cos[`NUM_WAY-1 :0]	;
	bit	signed[15:0]	nco_sin[`NUM_WAY-1 :0]	;
	bit	signed[15:0]	nco_cos_queue[$]	;
	bit	signed[15:0]	nco_sin_queue[$]	;

	bit	signed[15:0]	hilbert_in[$];
	bit	signed[15:0]	hilbert_out[$];

	bit signed[15:0]	iq_mod_data_i_queue[$];
	bit signed[15:0]	iq_mod_data_q_queue[$];

	bit	signed[31:0]	iq_mod_data_i_temp	;
	bit	signed[31:0]	iq_mod_data_q_temp	;
	bit	signed[31:0]	i_mult_cos;
	bit	signed[31:0]	i_mult_sin;
	bit	signed[31:0]	q_mult_cos;
	bit	signed[31:0]	q_mult_sin;

	bit	signed[15:0]	iq_mod_data_i[`NUM_WAY-1 :0]	;
	bit	signed[15:0]	iq_mod_data_q[`NUM_WAY-1 :0]	;

	bit	signed[15:0]	wave_mod_out[$]		;

//wave_amp output siganl
	bit [31:0]				wave_amp_out_temp;
	bit [`DATA_WIDTH-1:0] 	wave_amp_out[`NUM_WAY-1 :0];
//wave_mix output siganl
	bit [`DATA_WIDTH-1:0] 	wave_mix_out[`NUM_WAY-1:0];
	bit [`DATA_WIDTH-1:0] 	wave_mix_outb[`NUM_WAY-1:0];
//Pump & Mark signal


//wait sync signal
    	`uvm_info(get_type_name(),"awg wait sync_in",UVM_LOW)
    	wait (`SYNC_IN);
    	`uvm_info(get_type_name(),"awg sync_in come",UVM_LOW)


forever begin
	wait(cw_valid == 1);
	`uvm_info(get_type_name(),$sformatf("awg_cw_data = %h,wave_ctrl = %h,func_ctrl = %h",cw_data,wave_ctrl,func_ctrl),UVM_LOW)

//config signals
	mod_mode   = func_ctrl[1:0];
	clr_en	   = cw_data[6];
	loc_rst_n  = (mod_mode == 2'b01) | (mod_mode == 2'b11);
	hilbert_en = (mod_mode == 2'b01) | (mod_mode == 2'b10);
	iq_mod_en  = (mod_mode == 2'b01);
	mix_en 	   = ~func_ctrl[2];
	`uvm_info(get_type_name(),$sformatf("mod_mode = %h,clr_en = %h",mod_mode,clr_en),UVM_LOW);
	`uvm_info(get_type_name(),$sformatf("loc_rst_n = %h,hilbert_en = %h,iq_mod_en = %h",loc_rst_n,hilbert_en,iq_mod_en),UVM_LOW);

////////////////////////////////////////
//delay calculator
///////////////////////////////////////
//wave_play : 3
//hilbert   : 8
//nco 		: 11
//iq_mod+mux: 2 + 1 
//amp		: 1
//mix		: 1
//awg_out to dac_if :3
	awg_clock_cycle = clock_cycle + 3;							//wave_play
	case(mod_mode)
		2'b00 : awg_clock_cycle = awg_clock_cycle + 2 + 3;				//hilbert_in
		2'b01 : awg_clock_cycle = awg_clock_cycle + 8 + 2 + 1 + 2 + 3;	//iq_mod
		2'b10 : awg_clock_cycle = awg_clock_cycle + 8 + 1 + 2 + 3; 		//hilbert_q
		2'b11 : awg_clock_cycle = awg_clock_cycle + 8 + 1 + 2 + 3; 		//nco_cos
	endcase
	`uvm_info(get_type_name(),$sformatf("mod_mode = %0h,awg_clock_cycle = %0h",mod_mode,awg_clock_cycle),UVM_LOW);

	zeros_len = awg_clock_cycle - data_out_0.size() - dac_send_cnt * `DAC_MON_CYCLE;
	`uvm_info(get_type_name(),$sformatf("data_out_0.size() = %0h",data_out_0.size()),UVM_LOW);

	for (int i = 0; i < zeros_len; i++)begin
		data_out_0.push_back(16'h8000);
		data_out_1.push_back(16'h8000);
		data_out_2.push_back(16'h8000);
		data_out_3.push_back(16'h8000);
		data_out_4.push_back(16'h8000);
		data_out_5.push_back(16'h8000);
		data_out_6.push_back(16'h8000);
		data_out_7.push_back(16'h8000);
	
		data_outb_0.push_back(16'h8000);
		data_outb_1.push_back(16'h8000);
		data_outb_2.push_back(16'h8000);
		data_outb_3.push_back(16'h8000);
		data_outb_4.push_back(16'h8000);
		data_outb_5.push_back(16'h8000);
		data_outb_6.push_back(16'h8000);
		data_outb_7.push_back(16'h8000);
	end
	`uvm_info(get_type_name(),$sformatf("dac_send_cnt = %0h,zeros_len = %0h,data_out_0.size() = %0h",dac_send_cnt,zeros_len,data_out_0.size()),UVM_LOW);


/////////////////////////////////////////////
//AWG functions
/////////////////////////////////////////////

//wave_play
	wave_id		= cw_data[5 :0];
	env_map_addr= 25'hA00000 + {wave_id,2'b00};  
	env_idx	 	= ram_data.exists(env_map_addr) ? ram_data[env_map_addr] : 0;	 //get env_idx
	env_addr 	= 25'hB00000 + {env_idx[31:16],4'b0};	//start address  
	env_len		= env_idx[15:0];			//128bit -- 4'b0

	`uvm_info(get_type_name(),$sformatf("env_map_addr = %h,env_idx = %h",env_map_addr,env_idx),UVM_LOW);
	`uvm_info(get_type_name(),$sformatf("env_addr = %h,env_len = %h",env_addr,env_len),UVM_LOW);
	
	for(k =0; k<env_len; k++)begin
		wave_out_0 	= ram_data[env_addr];	

		env_addr_1	= env_addr + 4;
		env_addr_2	= env_addr + 8;
		env_addr_3	= env_addr + 12;

		wave_out_1 	= ram_data[env_addr_1];	
		wave_out_2 	= ram_data[env_addr_2];	
		wave_out_3 	= ram_data[env_addr_3];
		wave_out 	= {wave_out_3,wave_out_2,wave_out_1,wave_out_0};

		env_addr	= env_addr + 16;
		`uvm_info(get_type_name(),$sformatf("wave_out = %h,env_addr = %h",wave_out,env_addr),UVM_LOW);
	
//hilbert_fir
		for(j = 0; j<`NUM_WAY; j++)begin
			hilbert_in.push_back(wave_out[j*`DATA_WIDTH +:`DATA_WIDTH]) ; 
			`uvm_info(get_type_name(),$sformatf("hilbert_in[%0h] = %h",j,wave_out[j*`DATA_WIDTH +:`DATA_WIDTH]),UVM_LOW);
		end
	end
	`uvm_info(get_type_name(),$sformatf("hilbert_in_queue = %p,hilbert_in_queue.size",hilbert_in,hilbert_in.size()),UVM_LOW);
	hilbert_fir(hilbert_in,hilbert_in.size(),hilbert_out);

//wave_mode
	for(k =0; k<env_len; k++)begin
		frequency_48 = {1'b0,frequency,15'b0};
		`uvm_info(get_type_name(),$sformatf("frequency = %h,frequency_48 = %h,phase[31:16] = %h",frequency,frequency_48,phase[31:16]),UVM_LOW);
		`uvm_info(get_type_name(),$sformatf("clk_cycle = %h",k),UVM_LOW);
//nco dpi
		//DPI_nco_terminate(objhandle);
		objhandle=DPI_nco_initialize(objhandle);
		for (j = 0; j<`NUM_WAY; j++)begin
			DPI_nco(objhandle,real'(frequency_48),real'(phase[31:16]),real'(clr_en),real'(nco_acc_in + 2*(j+1)*frequency_48),nco_cos[j],nco_sin[j],nco_acc_out);
			nco_cos_queue.push_back(nco_cos[j]);
			nco_sin_queue.push_back(nco_sin[j]);

			`uvm_info(get_type_name(),$sformatf("nco_acc_in + 2*%0h * frequency = %h",j,(nco_acc_in + 2*(j+1)*frequency_48)),UVM_LOW);
			`uvm_info(get_type_name(),$sformatf("cos[%0h] = %h,sin[%0h] = %h,nco_acc_out  =%h ",j,nco_cos[j],j,nco_sin[j],nco_acc_out),UVM_LOW);
		end
		
		nco_acc_in = nco_acc_in + 16 * frequency_48;

//mod_i
		for(j = 0; j<`NUM_WAY; j++)begin
			i_mult_cos  = hilbert_in[j+k*`NUM_WAY]*nco_cos[j];
			q_mult_sin  = hilbert_out[j+k*`NUM_WAY]*nco_sin[j];
			iq_mod_data_i_temp = i_mult_cos - q_mult_sin;
			if(iq_mod_data_i_temp[31] == 1)begin
				if(iq_mod_data_i_temp[15:0] == 0)begin
					iq_mod_data_i[j]	= $floor(iq_mod_data_i_temp/32768);
				end else begin
					iq_mod_data_i[j]	= $floor(iq_mod_data_i_temp/32768)- 1;
				end
			end
			else begin
					iq_mod_data_i[j]	= $floor(iq_mod_data_i_temp/32768);
			end
		iq_mod_data_i_queue.push_back(iq_mod_data_i[j]);

//		`uvm_info(get_type_name(),$sformatf("hilbert_in[%0d+%0d*`NUM_WAY] = %h,nco_cos[%0d] = %h",j,k,hilbert_in[j+k*`NUM_WAY],j,nco_cos[j]),UVM_LOW);
//		`uvm_info(get_type_name(),$sformatf("hilbert_out[%0d+%0d*`NUM_WAY] = %h,nco_sin[%0d] = %h",j,k,hilbert_out[j+k*`NUM_WAY],j,nco_sin[j]),UVM_LOW);
//		`uvm_info(get_type_name(),$sformatf("i_mult_cos = %h,q_mult_sin = %h",i_mult_cos,q_mult_sin),UVM_LOW);

		`uvm_info(get_type_name(),$sformatf("iq_mod_data_i_temp = %h,iq_mod_data_i[%0h] = %h",iq_mod_data_i_temp,j,iq_mod_data_i[j]),UVM_LOW);
		end
//mod_q
		for(j = 0; j<`NUM_WAY; j++)begin
			i_mult_sin	=	hilbert_in[j+k*`NUM_WAY]*nco_sin[j];
			q_mult_cos	=	hilbert_out[j+k*`NUM_WAY]*nco_cos[j];
			iq_mod_data_q_temp = q_mult_cos + i_mult_sin;
			if(iq_mod_data_q_temp[31] == 1)begin
				if(iq_mod_data_q_temp[15:0] == 0)begin
					iq_mod_data_q[j]	= $floor(iq_mod_data_q_temp/32768);
				end else begin
					iq_mod_data_q[j]	= $floor(iq_mod_data_q_temp/32768)- 1;
				end
			end
			else begin
					iq_mod_data_q[j]	= $floor(iq_mod_data_q_temp/32768);
			end
		iq_mod_data_q_queue.push_back(iq_mod_data_q[j]);

//			iq_mod_data_q[j]   = {iq_mod_data_q_temp[31],iq_mod_data_q_temp[29:15]};
		`uvm_info(get_type_name(),$sformatf("iq_mod_data_q_temp = %h,iq_mod_data_q[%0h] = %h",iq_mod_data_q_temp,j,iq_mod_data_q[j]),UVM_LOW);
		end

	end

//mux
	case(mod_mode)
		2'b00 : wave_mod_out = hilbert_in;
		2'b01 : wave_mod_out = iq_mod_data_i_queue;
		2'b10 : wave_mod_out = hilbert_out;
		2'b11 : wave_mod_out = nco_cos_queue;
	endcase
	`uvm_info(get_type_name(),$sformatf("wave_mod_out = %p,wave_mod_out.size()=%0h",wave_mod_out,wave_mod_out.size()),UVM_LOW);
	
//wave_amp,mix
	`uvm_info(get_type_name(),$sformatf("AMP = %0h",amplitude[31:16]),UVM_LOW);
	for(k =0; k<env_len; k++)begin
		for(j = 0; j<`NUM_WAY; j++)begin
			wave_amp_out_temp 	  = wave_mod_out[j+k*`NUM_WAY] * $signed(amplitude[31:16]);
			wave_amp_out[j] 	  = $rtoi(wave_amp_out_temp/16384);
			`uvm_info(get_type_name(),$sformatf("wave_mod_out = %0h,wave_amp_out_temp=%0h,wave_amp_out[%0h] = %0h",wave_mod_out[j+k*`NUM_WAY],wave_amp_out_temp,j,wave_amp_out[j]),UVM_LOW);
	
			wave_mix_out[j]		  = wave_amp_out[j]^{1'b1, {`DATA_WIDTH-1{1'b0}}};
			if(mix_en)begin
				wave_mix_outb[j] = ~wave_mix_out[j]+1'b1;
			end else begin
				wave_mix_outb[j] = wave_mix_out[j];
			end
		`uvm_info(get_type_name(),$sformatf("mix_en = %0h,wave_mix_out[%0h] = %0h,wave_mix_outb[%0h] = %0h",mix_en,j,wave_mix_out[j],j,wave_mix_outb[j]),UVM_LOW);	
		end
	
		data_out_0.push_back(wave_mix_out[0]);
		data_out_1.push_back(wave_mix_out[1]);
		data_out_2.push_back(wave_mix_out[2]);
		data_out_3.push_back(wave_mix_out[3]);
		data_out_4.push_back(wave_mix_out[4]);
		data_out_5.push_back(wave_mix_out[5]);
		data_out_6.push_back(wave_mix_out[6]);
		data_out_7.push_back(wave_mix_out[7]);
	
		data_outb_0.push_back(wave_mix_outb[0]);
		data_outb_1.push_back(wave_mix_outb[1]);
		data_outb_2.push_back(wave_mix_outb[2]);
		data_outb_3.push_back(wave_mix_outb[3]);
		data_outb_4.push_back(wave_mix_outb[4]);
		data_outb_5.push_back(wave_mix_outb[5]);
		data_outb_6.push_back(wave_mix_outb[6]);
		data_outb_7.push_back(wave_mix_outb[7]);
	
	end
	`uvm_info(get_type_name(),$sformatf("push_data_out_0.size() = %0h",data_out_0.size()),UVM_LOW);

	cw_valid = 0;
	nco_acc_out = 0;
	nco_acc_in  = 0;
	hilbert_in.delete();

	nco_cos_queue.delete();
	nco_sin_queue.delete();
                            
	iq_mod_data_i_queue.delete();
	iq_mod_data_q_queue.delete();
end

endtask

task readout_awg_rm::if_pump_mark();
//item
	mcu_cw_item mcu_cw_item;
//pump and mark signal
	bit [31:0]	wait_cycle = 100;
	bit	[31:0]	cnt;
	bit			pump_flag = 1'b1;
	bit			mark_flag = 1'b1;
	bit	[31:0]  cw_data_if;
	bit			pump_trig ;
	bit			mark_trig ;

	bit [3 :0] 	align_del;
	bit	[15:0]	pump_delay;
	bit	[15:0]	pump_width;

	bit	[15:0]	mark_delay;
	bit	[15:0]	mark_width;

	wait(`SYNC_IN)
	`uvm_info(get_type_name(),("if_pump_mark.sync_in "),UVM_LOW);

	forever begin
//pump
		@(posedge `CLK);
		cnt++;
		rm_if.cnt = cnt;
		if(cw_queue.size()>0 && pump_flag == 1 && mark_flag == 1)begin
			mcu_cw_item = cw_queue.pop_front();
			wait_cycle 	= mcu_cw_item.clock_cycle;
			cw_data_if	= mcu_cw_item.cw_data;

			pump_flag = 1'b0;
			mark_flag = 1'b0;	
			pump_trig  = cw_data_if[8];
			mark_trig  = cw_data_if[9];
			`uvm_info(get_type_name(),$sformatf("pump_trig = %0h,mark_trig = %0h",pump_trig,mark_trig),UVM_LOW);
			`uvm_info(get_type_name(),$sformatf("wait_cycle = %0h,cw_data_if= 0%h",wait_cycle,cw_data_if),UVM_LOW);

			case (func_ctrl[1:0])
				2'b00 : align_del = 4'h0;
				2'b01 : align_del = 4'ha;
				2'b10 : align_del = 4'h8;
				2'b11 : align_del = 4'h8;
			endcase

			pump_delay = pump_ctrl[31:16] + align_del + 2;	//compare to cw_valid
			pump_width = pump_ctrl[15:0]  + env_len;
			`uvm_info(get_type_name(),$sformatf("pump_delay = %0h,pump_width = %0h,align_del = %0h",pump_delay,pump_width,align_del),UVM_LOW);

			mark_delay = mark_ctrl[31:16] + 2;				//compare to cw_valid
			mark_width = mark_ctrl[15:0];
			`uvm_info(get_type_name(),$sformatf("mark_delay = %0h,mark_width = %0h",mark_delay,mark_width),UVM_LOW);
		end	

		fork 
			if(cnt == wait_cycle)begin
				repeat(pump_delay)begin
					rm_if.pump_rm = func_ctrl[4];
					@(posedge `CLK);
				end
				repeat(pump_width)begin
					if(pump_trig)begin
						rm_if.pump_rm = ~func_ctrl[4];
						@(posedge `CLK);
					end 
					else begin
						rm_if.pump_rm = func_ctrl[4];
						@(posedge `CLK);
					end
				end
					rm_if.pump_rm = 1'b0;
					pump_flag = 1;
			end
//mark
			if(cnt == wait_cycle)begin
				repeat(mark_delay)begin
					rm_if.mark_rm = func_ctrl[5];
					@(posedge `CLK);
				end
				repeat(mark_width)begin
					if(mark_trig)begin
						rm_if.mark_rm = ~func_ctrl[5];
						@(posedge `CLK);
					end 
					else begin
						rm_if.mark_rm = func_ctrl[5];
						@(posedge `CLK);
					end
				end
					rm_if.mark_rm = 1'b0;
					mark_flag = 1;
			end

			if(cnt == wait_cycle)begin
				if(pump_delay + pump_width >= mark_delay + mark_width)begin
					repeat(pump_delay + pump_width)begin
						cnt++;
						rm_if.cnt = cnt;
						@(posedge `CLK);
					end
				end 
				else begin
					repeat(mark_delay + mark_width)begin
						cnt++;
						rm_if.cnt = cnt;
						@(posedge `CLK);
					end
				end
			end
		join
	end
endtask


task readout_awg_rm::hilbert_fir( 
	input 	bit signed[15:0] 	hilbert_in[$],
	input	bit		  [15:0]		data_size,
	output 	bit signed[15:0]	hilbert_out[$]
);
	localparam	COEFF_LEN = 33;

    bit signed [15:0] coeff [0:COEFF_LEN-1] = {
        16'd0,   -16'd69, 16'd0,   -16'd202, 16'd0,   -16'd471,
        16'd0,   -16'd950, 16'd0,  -16'd1766, 16'd0,  -16'd3213,
        16'd0,   -16'd6337, 16'd0, -16'd20648, 16'd0, 16'd20648,
        16'd0,   16'd6337, 16'd0,  16'd3213,  16'd0,  16'd1766,
        16'd0,   16'd950,  16'd0,  16'd471,   16'd0,  16'd202,
        16'd0,   16'd69,   16'd0
    };	
	bit signed	[31:0]	acc ;
	bit signed  [31:0]  mul;
//conv
	`uvm_info(get_type_name(),$sformatf("hilbert_in_queue = %p",hilbert_in),UVM_LOW);
	`uvm_info(get_type_name(),$sformatf("coeff = %p,data_size = %0d",coeff,data_size),UVM_LOW);

    for (int i = 0; i < COEFF_LEN + data_size; i++) begin
		for (int j = 0 ; j <= i; j++)begin
        	mul = coeff[i-j] * hilbert_in[j];
			acc = acc + mul;
//			`uvm_info(get_type_name(),$sformatf("coeff[%0d-%0d] = %0d ,hilbert_in[%0d] = %0d",i,j,coeff[i-j],j,hilbert_in[j]),UVM_LOW);
		
//			`uvm_info(get_type_name(),$sformatf("mul = %0d, mul[31:16] = %0d,acc = %0d",mul,$signed(mul[31:16]),acc),UVM_LOW);
        end 		

		if(acc[31] == 1)begin
			if(acc[15:0] == 0)begin
				hilbert_out[i]	= $floor(acc/32768);
			end else begin
				hilbert_out[i]	= $floor(acc/32768)- 1;
			end
		end
		else begin
				hilbert_out[i]	= $floor(acc/32768);
		end

	//	hilbert_out[i] = $floor(acc/32768);
		`uvm_info(get_type_name(),$sformatf("acc = %0d ,acc[31:16] = %0d,hilbert_out = %0d",acc,$floor(acc/32768),hilbert_out[i]),UVM_LOW);
		acc = 32'b0;
    end	
`uvm_info(get_type_name(),$sformatf("hilbert_out = %p,hilbert_out.size() = %d",hilbert_out,hilbert_out.size()),UVM_LOW);

	hilbert_out = hilbert_out[16:COEFF_LEN + data_size-18];
`uvm_info(get_type_name(),$sformatf("hilbert_out = %p,hilbert_out.size() = %d",hilbert_out,hilbert_out.size()),UVM_LOW);


endtask



task readout_awg_rm::run_phase(uvm_phase phase);
	fork
		get_mcu_cw_item();
		get_spi_item();
		get_config_data();
		awg_exe();
		if_pump_mark();
		send_dac_item();
	join
endtask




`endif
