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

//问题待解决：数据类型定义
//pulsewidth信号定义在mcu_reg中


`ifdef  READOUT_AWG_RM
`define READOUT_AWG_RM

//import uvm_pkg::*;
import nco_dpi_pkg::*;
import hilbert_fir_dpi_pkg::*;

class readout_awg_rm extends uvm_component;
	virtual rm_if rm_if; 	//clk和sync

	uvm_blocking_get_export #(EZQ_readout_dac_item)  dac_rm2scb_port;		//wave输出给scoreboard
	uvm_blocking_get_port #(mcu_item)  mcu_get_port; 					 //从mcu获取带时间戳的包，包含cw，time

	EZQ_readout_dac_item dac_item_pkt;
	mcu_item 		     mcu_item_pkt;

	`uvm_component_utils(readout_awg_rm);

	static int NUM_WAY = 8;
	static int DATA_WIDTH = 16;

    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 wave_play(		//根据cw获取波形数据
		logic [5:0] wave_id,
		logic [DATA_WIDTH*NUM_WAY-1:0] wave_mem_out[$],
		logic [15:0] wave_len;

		logic [15:0]time_in,
		logic [15:0]time_out
    );

    extern task wave_mode(		//awg算法
		logic        clr_valid,		//sync
		logic 		 clr_en,		//cw_data[6]
		logic [1 :0] mod_mode,		//func_ctrl[1:0]
		logic [31:0] fcw,
		logic [15:0] phase,			//phase[31:16]

		logic [DATA_WIDTH*NUM_WAY-1:0] wave_in,
		logic [DATA_WIDTH-1:0] wave_mod_out[NUM_WAY],

		logic [15:0]time_in,
		logic [15:0]time_out
    );

    extern task wave_amp(
	    logic [15:0] 		   amplitude,   //amp[31:16]
	    logic [DATA_WIDTH-1:0] wave_amp_in[NUM_WAY],
	    logic [DATA_WIDTH-1:0] wave_amp_out[NUM_WAY],
	    logic [15:0]time_in,
	    logic [15:0]time_out
    );

    extern task wave_mix(
		logic 		 mix_en , //~func_ctrl[2]
		logic [DATA_WIDTH-1:0] wave_in[NUM_WAY],
		logic [DATA_WIDTH*NUM_WAY-1:0] wave_mix_out,
		logic [DATA_WIDTH*NUM_WAY-1:0] wave_mix_outb,
		logic [15:0]time_in,
		logic [15:0]time_out
	);
/*
    extern task pulse_generator_pump(
    	logic 		 pulse_en ,
    	logic [15:0] delay,
        logic [31:0] width,
    	logic 		 inv_en ,
    	logic [15:0] pulse
	);
*/
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::run_phase(uvm_phase phase);//main task
//cw
	logic	     clk;
	logic [31:0] cw_data;
	logic		 sync;
//awg config signal
	logic [31:0] mcu_timer,
	logic [31:0] mcu_counter,
	logic [31:0] pulse_width,

	logic [31:0] amplitude,
	logic [31:0] frequency,
	logic [31:0] phase,

	logic [31:0] loc_state,
	logic [31:0] glb_state,
	logic [31:0] feed_data,
//control signal
    logic [31:0] command;
    logic [31:0] func_ctrl;
    logic [31:0] pump_ctrl;
    logic [31:0] mark_ctrl;
//get wave_idx & wave
	logic [DATA_WIDTH*NUM_WAY-1:0] wave_mem_out[$];
//wave_mod output signal
	logic [DATA_WIDTH-1:0] wave_mod_out[NUM_WAY];
//wave_amp output siganl
	logic [DATA_WIDTH-1:0] wave_amp_out[NUM_WAY];
//wave_mix output siganl
	logic [DATA_WIDTH*NUM_WAY-1:0] wave_mix_out;
	logic [DATA_WIDTH*NUM_WAY-1:0] wave_mix_outb;
//wave_out queue
	logic [DATA_WIDTH*NUM_WAY-1:0] wave_out_list[$];
	logic [DATA_WIDTH*NUM_WAY-1:0] wave_outb_list[$];
//Pump & Mark signal
	logic 		 pump_trig;
	logic 		 mark_trig;
	logic 		 pump_delay;
	logic 		 mark_delay;
	logic [15:0] pump_width;
	logic [15:0] mark_width;
//时间戳，mcu_item_pkt到来时，继承pkt中的时间
	logic [15:0] time_cw;
	logic [15:0] time_play;
	logic [15:0] time_mode;
	logic [15:0] time_amp;
	logic [15:0] time_mix;

// sync signal
	sync		 = rm_if.sync;

//MCU packet
	mcu_get_port.get(mcu_item_pkt);
	time_cw      = mcu_item_pkt.clock_cycle;
	cw_data		 = mcu_item_pkt.cw_data;
	pulse_width  = mcu_item_pkt.pulse_width;//该信号通过MCU的packet传送

//AWG reg
	frequency    = reg_mems::awg_regfile.get("Frequency");
	phase        = reg_mems::awg_regfile.get("Phase");
	amplitude    = reg_mems::awg_regfile.get("Amplitude");

	mcu_timer    = reg_mems::awg_regfile.get("Timer");
	mcu_counter  = reg_mems::awg_regfile.get("Counter");

	loc_state    = reg_mems::awg_regfile.get("LOC_State");
	glb_state    = reg_mems::awg_regfile.get("GLB_State");
	feed_data    = reg_mems::awg_regfile.get("FEED_Data");

	func_ctrl    = reg_mems::awg_regfile.get("Function");
	command		 = reg_mems::awg_regfile.get("Command");
	pump_ctrl    = reg_mems::awg_regfile.get("pump_ctrl");
	mark_ctrl	 = reg_mems::awg_regfile.get("maker_ctrl");

//AWG functions
	wave_play(
	.wave_id(cw_data[5:0]),
	.wave_mem_out(wave_mem_out),
	.wave_len(wave_len)
	.time_in(time_cw),
	.time_out(time_play)
	);

for(k=0;k<wave_len;k++)begin
	wave_mode(
	.clr_valid(sync),
	.clr_en(cw_data[6]),
	.mod_mode(func_ctrl[1:0]),
	.fcw(frequency),
	.phase(phase[31:16]),
	.wave_in(wave_mem_out[k]),
	.wave_mod_out(wave_mod_out)
	.time_in(time_play),
	.time_out(time_mode)
	);

	wave_amp(
	.amplitude(amplitude[31:16]),   //amp[31:16]
	.wave_amp_in(wave_mod_out),
	.wave_amp_out(wave_amp_out),
	.time_in(time_mode),
	.time_out(time_amp)
	);

	wave_mix(
    .mix_en(~func_ctrl[2]) , //~func_ctrl[2]
    .wave_in(wave_amp_out),
    .wave_mix_out(wave_mix_out),
    .wave_mix_outb(wave_mix_outb),
	.time_in(time_amp),
	.time_out(time_mix)
	);
	wave_out_list.push_back (wave_mix_out);
	wave_outb_list.push_back(wave_mix_outb);
end
//send to scoreboard
	dac_item_pkt.cycle    = time_mix;

for (k=0;k<wave_len;k++)begin
	dac_item_pkt.data_out0[k] = wave_out_list[k][0*DATA_WIDTH:1*DATA_WIDTH-1];
	dac_item_pkt.data_out1[k] = wave_out_list[k][1*DATA_WIDTH:2*DATA_WIDTH-1];
	dac_item_pkt.data_out2[k] = wave_out_list[k][2*DATA_WIDTH:3*DATA_WIDTH-1];
	dac_item_pkt.data_out3[k] = wave_out_list[k][3*DATA_WIDTH:4*DATA_WIDTH-1];
	dac_item_pkt.data_out4[k] = wave_out_list[k][4*DATA_WIDTH:5*DATA_WIDTH-1];
	dac_item_pkt.data_out5[k] = wave_out_list[k][5*DATA_WIDTH:6*DATA_WIDTH-1];
	dac_item_pkt.data_out6[k] = wave_out_list[k][6*DATA_WIDTH:7*DATA_WIDTH-1];
	dac_item_pkt.data_out7[k] = wave_out_list[k][7*DATA_WIDTH:8*DATA_WIDTH-1];

	dac_item_pkt.data_outb0[k]= wave_outb_list[k][0*DATA_WIDTH:1*DATA_WIDTH-1];
	dac_item_pkt.data_outb1[k]= wave_outb_list[k][1*DATA_WIDTH:2*DATA_WIDTH-1];
	dac_item_pkt.data_outb2[k]= wave_outb_list[k][2*DATA_WIDTH:3*DATA_WIDTH-1];
	dac_item_pkt.data_outb3[k]= wave_outb_list[k][3*DATA_WIDTH:4*DATA_WIDTH-1];
	dac_item_pkt.data_outb4[k]= wave_outb_list[k][4*DATA_WIDTH:5*DATA_WIDTH-1];
	dac_item_pkt.data_outb5[k]= wave_outb_list[k][5*DATA_WIDTH:6*DATA_WIDTH-1];
	dac_item_pkt.data_outb6[k]= wave_outb_list[k][6*DATA_WIDTH:7*DATA_WIDTH-1];
	dac_item_pkt.data_outb7[k]= wave_outb_list[k][7*DATA_WIDTH:8*DATA_WIDTH-1];
end

//pump and mark signal
	pump_trig  = cw_data[8];
	mark_trig  = cw_data[9];
	pump_delay = pump_ctrl[31:16];
	mark_delay = mark_ctrl[31:16];
	pump_width = func_ctrl[6] ? pulse_width[15:0]  : pump_ctrl[15:0];
	mark_width = func_ctrl[7] ? pulse_width[31:16] : mark_ctrl[15:0];

//pump和mark信号的输出时间、输出宽度和输出极性
	if(pump_trig)begin
		rm_if.pump_width = pump_width;
		rm_if.pump_rm    = ~func_ctrl[4];
		rm_if.pump_time  = time_cw + pump_delay;
	end else begin
		rm_if.pump_width = 0;
		rm_if.pump_rm    = func_ctrl[4];
		rm_if.pump_time  = 0;
	end
	if(mark_trig)begin
		rm_if.mark_width = mark_width;
		rm_if.mark_rm    = ~func_ctrl[5];
		rm_if.mark_time  = time_cw + mark_delay;
	end else begin
		rm_if.mark_width = 0;
		rm_if.mark_rm    = func_ctrl[5];
		rm_if.mark_time  = 0;
	end
endtask

task readout_awg_rm::wave_play(
	logic [5:0] wave_id,
	logic [DATA_WIDTH*NUM_WAY-1:0] wave_mem_out[$],
	logic [15:0] wave_len;

	logic [15:0]time_in,
	logic [15:0]time_out
);
	logic [31:0] get_wave_idx_len;
	logic [15:0] wave_addr;
	logic [15:0] wave_len;
	logic [DATA_WIDTH*NUM_WAY-1:0]wave_out[wave_len]; //wave_len个8*16bit数据

	time_out = time_in + 16'd4;

	reg_mems::env_indx_ram.get32bit({wave_id[5:0],2'b00},get_wave_idx_len); //获取wave地址和长度
	wave_addr 	= {get_wave_idx_len[31:16],4'b0};
	wave_len	= get_wave_idx_len[15: 0];
	$display("wave_addr and wave_len is %b %d",wave_addr,wave_len);

	reg_mems::env_data_ram.get32bit(wave_addr,wave_out);    //获取wave波形数据

	foreach (wave_out[i])begin
	wave_mem_out.push_back(wave_out[i]);
	$display("wave %d is %b ",i,wave_out[i]);
	end
endtask

task readout_awg_rm::wave_mode(
	logic        clr_valid,		//sync
    logic 		 clr_en,		//cw_data[6]
	logic [1 :0] mod_mode,		//func_ctrl[1:0]
	logic [31:0] fcw,
    logic [15:0] phase,			//phase[31:16]

	logic [DATA_WIDTH*NUM_WAY-1:0] wave_in,
	logic [DATA_WIDTH-1:0] wave_mod_out[NUM_WAY],

	logic [15:0]time_in,
	logic [15:0]time_out
);
//hilbert signal
	logic  		 		   hilbert_en;
	logic [DATA_WIDTH-1:0] hilbert_in[NUM_WAY];
	real				   dpi_hilbert_out_i[NUM_WAY];
	real				   dpi_hilbert_out_q[NUM_WAY];
	logic [DATA_WIDTH-1:0] hilbert_out_i[NUM_WAY];
	logic [DATA_WIDTH-1:0] hilbert_out_q[NUM_WAY];
//nco signal
	logic		 loc_rst_n;
	logic		 clr_en;
	logic [63:0] result_cos;
	logic [63:0] result_sin;
	logic [63:0] result_acc;
	logic [15:0] cos_list[$];
	logic [15:0] sin_list[$];
//mod signal
	logic 		 		     iq_mod_en;
	logic [DATA_WIDTH*2-1:0] iq_mod_data_i_temp;
	logic [DATA_WIDTH-1:0]   iq_mod_data_i[NUM_WAY];
//	logic [DATA_WIDTH-1:0] iq_mod_data_q[NUM_WAY];

//inter signal
	loc_rst_n  = ((mod_mode[1:0] == 2'b01) | (mod_mode[1:0] == 2'b11));
	hilbert_en = (mod_mode[1:0] == 2'b01) | (mod_mode[1:0] == 2'b10);
	iq_mod_en  = (mod_mode[1:0] == 2'b01);

//time_delay
	if (mod_mode[1:0] == 2'b11)	//nco out
		time_out = time_in + 16'd8 + 16'd1;
	else  begin
	if(hilbert_en & iq_mod_en) //iq_mod out
		time_out = time_in + 16'd8 + 16'd2 + 16'd1;
	else if(hilbert_en & !iq_mod_en) //hilbert out
		time_out = time_in + 16'd8 + 16'd1;
	else (!hilbert_en)//wave_mem out
		time_out = time_in + 16'd1;
	end
//NCO dpi
	objhandle=DPI_nco_initialize(objhandle);
	for (k=0;k<NUM_WAY-1;k++)begin
	//DPI_nco_terminate(objhandle);
	DPI_nco(objhandle,real(fcw),real(phase),real(clr_en),real(k*fcw),result_cos,result_sin,result_acc);
	cos_list.push_back(shortint(result_cos));
    sin_list.push_back(shortint(result_sin));
	end

//hilbert dpi
	for(k=0;k<NUM_WAY;k++)begin
		hilbert_in[k] = wave_in[k*DATA_WIDTH:(k+1)*DATA_WIDTH-1];   //将128bit数据拆分为16bit*8
	end
    OBJhandle=DPI_hilbert_fir_initialize(OBJhandle);
   //DPI_hilbert_fir_terminate(OBJhandle);
	DPI_hilbert_fir(OBJhandle,real(hilbert_in),dpi_hilbert_out_i,dpi_hilbert_out_q);//输入输出均为数组
	hilbert_out_i = shortint(dpi_hilbert_out_i);
	hilbert_out_q = shortint(dpi_hilbert_out_q);

	foreach (hilbert_out_i[index])
	$display("hilbert_out_i is :%b",hilbert_out_i[index]);
	foreach (hilbert_out_q[index])
	$display("hilbert_out_q is :%b",hilbert_out_q[index]);
//mod
	for(k=0;k<NUM_WAY;k++)begin
		iq_mod_data_i_temp = hilbert_out_i[k]*cos_list[k]-hilbert_out_q[k]*sin_list[k];
		iq_mod_data_i[k]   = {iq_mod_data_i_temp[31],iq_mod_data_i_temp[29:15]};
	if(iq_mod_data_i[k]>32767)   iq_mod_data_i[k] = 32767;
	if(iq_mod_data_i[k]<-32767)  iq_mod_data_i[k] = -32767;
	end

	for(k=0;k<NUM_WAY;k++)begin
		iq_mod_data_q_temp = hilbert_out_q[k]*cos_list[k]+hilbert_out_i[k]*sin_list[k];
		iq_mod_data_q[k]   = {iq_mod_data_q_temp[31],iq_mod_data_q_temp[29:15]};
	if(iq_mod_data_q[k]>32767)   iq_mod_data_q[k] = 32767;
	if(iq_mod_data_q[k]<-32767)  iq_mod_data_q[k] = -32767;
	end

	foreach (iq_mod_data_i[index])
	$display("iq_mod_data_i is :%b",iq_mod_data_i[index]);
//mux
	case(mod_mode)
		2'b00 : wave_mod_out = hilbert_in;
		2'b01 : wave_mod_out = iq_mod_data_i;
		2'b10 : wave_mod_out = hilbert_out_q;
		2'b11 : wave_mod_out = cos_list;
	endcase

task readout_awg_rm::wave_amp(
	logic [15:0] 		   amplitude,   //amp[31:16]
	logic [DATA_WIDTH-1:0] wave_amp_in[NUM_WAY],
	logic [DATA_WIDTH-1:0] wave_amp_out[NUM_WAY],
	logic [15:0]time_in,
	logic [15:0]time_out
);
	time_out = time_in +16'd1;

	logic [DATA_WIDTH*2-1:0]wave_amp_out_temp;
	for(k=0;k<NUM_WAY-1;k++)begin
		wave_amp_out_temp 	  = wave_amp_in[k] * amplitude;
		wave_amp_out[k] 	  = {wave_amp_out_temp[31],wave_amp_out_temp[29:15]};
		if(wave_amp_out[k]>32767)   wave_amp_out[k] = 32767;
		if(wave_amp_out[k]<-32767)  wave_amp_out[k] = -32767;
	end
endtask

task wave_mix(
    logic 		 mix_en , //~func_ctrl[2]
    logic [DATA_WIDTH-1:0] wave_in[NUM_WAY],
    logic [DATA_WIDTH*NUM_WAY-1:0] wave_mix_out,
    logic [DATA_WIDTH*NUM_WAY-1:0] wave_mix_outb,
	logic [15:0]time_in,
	logic [15:0]time_out
);
	if(mix_en)
	time_out = time_in +16'd1;
	else
	time_out = time_in;

	for(k=0;k<NUM_WAY;k++)begin
		wave_mix_out[k*DATA_WIDTH:(k+1)*DATA_WIDTH-1] = wave_in[k]^{1'b1, {DATA_WIDTH-1{1'b0}}};//unsign to sign
	end

	if(mix_en)
	for(k=0;k<NUM_WAY;k++)begin
		wave_mix_outb[k*DATA_WIDTH:(k+1)*DATA_WIDTH-1] = ~wave_mix_out[k*DATA_WIDTH:(k+1)*DATA_WIDTH-1]+1'b1;//unsign to sign
	end else
	for(k=0;k<NUM_WAY;k++)begin
		wave_mix_outb[k*DATA_WIDTH:(k+1)*DATA_WIDTH-1] =  wave_mix_out[k*DATA_WIDTH:(k+1)*DATA_WIDTH-1];
	end

	foreach (wave_mix_out[index])
	$display("wave_mix_out is :%b",wave_mix_out[index]);
	foreach (wave_mix_outb[index])
	$display("wave_mix_outb is :%b",wave_mix_outb[index]);

endtask

`endif