//FILE_HEADER-------------------------------------------------------
//FILE_NAME       : EZQ_readout_refm.sv
//DEPARTEMENT     : Hfnl-cmos
//AUTHOR          :  
//EMAIL           :  
//*******************************************************************
//DESCRIPTION     : reference model define
//*******************************************************************
//END_HEADER*********************************************************
`ifndef EZQ_READOUT_REFM
`define EZQ_READOUT_REFM

`include "../testbench/refm/mcu_cw_item.sv"
`include "../testbench/refm/spi_rw.sv"
`include "../testbench/refm/reg_mems.sv"

class EZQ_readout_refm extends uvm_component;

     `uvm_component_utils(EZQ_readout_refm);

     virtual rm_if rm_if;
     uvm_blocking_get_export #(spi_item)                spi_get_port;
     uvm_blocking_get_export #(EZQ_readout_adc_item)    adc_get_port;
     uvm_analysis_port #(spi_item)                      spi_rm2scb_port;
     uvm_analysis_port #(EZQ_readout_dac_item)          dac_rm2scb_port;
     uvm_analysis_port #(mcu_cw_item)                      mcu_2awgrm_port;
     uvm_analysis_port #(mcu_cw_item)                      mcu_2daqrm_port;
     mcu_cw_item awg_mcu_cw_item_q[$];
     mcu_cw_item daq_mcu_cw_item_q[$];

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


    //bit[31:0] awg_mcu_inst_ram[bit[14:0]];
    //bit[31:0] awg_mcu_ram_data[bit[31:0]];
    bit[31:0] awg_mcu_reg[bit[31:0]];
    bit       awg_mcu_finish;

    //bit[31:0] daq_mcu_inst_ram[bit[14:0]];
    //bit[31:0] daq_mcu_ram_data[bit[31:0]];
    bit[31:0] daq_mcu_reg[bit[31:0]];
    bit       daq_mcu_finish;
    mcu_cw_item awg_mcu_cw_item_2scb_q[$];
    mcu_cw_item daq_mcu_cw_item_2scb_q[$];





/*
    parameter RW_TEST = 32'h0;
    parameter INTR_MASK = 32'h14;
    parameter SYS_FUNC = 32'h1c;
    parameter AWG_AMPLITUDE = 32'h900034;
    parameter AWG_FREQUENCY = 32'h900038;
    parameter AWG_PHASE = 32'h90003c; 
    parameter AWG_FUNC = 32'h900044;
    parameter AWG_PUMP_CTRL = 32'h900048;
    parameter AWG_MARKER_CTRL = 32'h90004c;
    parameter DAQ_SEND_DATA = 32'h400034;
    parameter DAQ_FREQUENCY = 32'h400038;
    parameter DAQ_PHASE = 32'h40003c;
    parameter DAQ_FUNC = 32'h400044;
    parameter WAVE_SAMPLE_DEPTH = 32'h400048;
    parameter DEMOD_WIN_WIDTH = 32'h40004c;
    parameter READ_THRESHOLD = 32'h400050;
    parameter READ_REQ_CTRL = 32'h400058;
    parameter DEMOD_WIDTH_Q0 = 32'h400080;
    parameter DEMOD_WIDTH_Q1 = 32'h400084;
    parameter DEMOD_WIDTH_Q2 = 32'h400088;
    parameter DEMOD_WIDTH_Q3 = 32'h40008c;
    parameter DEMOD_WIDTH_Q4 = 32'h400090;
    parameter DEMOD_WIDTH_Q5 = 32'h400094;
    parameter DEMOD_WIDTH_Q6 = 32'h400098;
    parameter DEMOD_WIDTH_Q7 = 32'h40009c;
    parameter DEMOD_WIDTH_Q8 = 32'h4000a0;
    parameter DEMOD_WIDTH_Q9 = 32'h4000a4;
    parameter DEMOD_WIDTH_Q10 = 32'h4000a8;
    parameter DEMOD_WIDTH_Q11 = 32'h4000ac;
    parameter DEMOD_WIDTH_Q12 = 32'h4000b0;
    parameter DEMOD_WIDTH_Q13 = 32'h4000b4;
    parameter DEMOD_WIDTH_Q14 = 32'h4000b8;
    parameter DEMOD_WIDTH_Q15 = 32'h4000bc;
*/

    bit[31:0] rw_test;
    bit[31:0] intr_mask;
    bit[31:0] sys_func;
    bit[31:0] awg_amplitude;
    bit[31:0] awg_frequency;
    bit[31:0] awg_phase;
    bit[31:0] awg_func;
    bit[31:0] awg_pump_ctrl;
    bit[31:0] awg_marker_en;
    bit[31:0] daq_send_data;
    bit[31:0] daq_frequency;
    bit[31:0] daq_phase;
    bit[31:0] wave_smaple_depth;
    bit[31:0] demod_win_width;
    bit[31:0] read_threshold;
    bit[31:0] read_req_ctrl;
    bit[31:0] demod_width_q0;
    bit[31:0] demod_width_q1;
    bit[31:0] demod_width_q2;
    bit[31:0] demod_width_q3;
    bit[31:0] demod_width_q4;
    bit[31:0] demod_width_q5;
    bit[31:0] demod_width_q6;
    bit[31:0] demod_width_q7;
    bit[31:0] demod_width_q8;
    bit[31:0] demod_width_q9;
    bit[31:0] demod_width_q10;
    bit[31:0] demod_width_q11;
    bit[31:0] demod_width_q12;
    bit[31:0] demod_width_q13;
    bit[31:0] demod_width_q14;
    bit[31:0] demod_width_q15;

    bit awg_mcu_finish;
    bit daq_mcu_finish;

     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_spi_item;
     extern task get_config_data();
     extern task mcu_process(bit [31:0] base_addr,ref bit[31:0] inst_ram[bit[31:0]],ref bit[31:0] mcu_reg[bit[31:0]],ref bit [31:0]ram_data[bit[31:0]],ref bit mcu_finish,ref mcu_cw_item mcu_cw_item_q[$]);
     extern task send_awg_codeword();
     extern task send_daq_codeword();


endclass : EZQ_readout_refm

function EZQ_readout_refm::new(string name,uvm_component parent);

	super.new(name,parent);

endfunction : new

function void EZQ_readout_refm::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"});
    spi_get_port = new("spi_get_port",this);
    adc_get_port = new("adc_get_port",this);    
    spi_rm2scb_port = new("spi_rm2scb_port",this);
    dac_rm2scb_port = new("dac_rm2scb_port",this);
endfunction

task EZQ_readout_refm::get_spi_item();
    forever begin
        spi_item spi_item;
        bit [31:0] wr_addr;
        bit [31:0] wr_data;
        bit [31:0] data_size;
        spi_get_port.get(spi_item);
        data_size = spi_item.data.size();
        for (int i=0;i<data_size;i++) begin
            wr_addr = spi_item.addr+i*32'h4;
            wr_data = spi_item.data.pop_front();
           /* if(wr_addr==`DAQ_FREQUENCY || wr_addr== `DAQ_PHASE || wr_addr==`DAQ_SEND_DATA) begin 
                `uvm_error(get_type_name(),$sformatf("spi can read this addr(%h) only",wr_addr))
            end*/
            `uvm_info(get_type_name(),$sformatf("write ram_data[%0h]=%0h",wr_addr,wr_data),UVM_LOW)
            ram_data[wr_addr] = wr_data;

	spi_rw spi_rw;
	spi_rw.rw(spi_item);
        end
    end
endtask

task EZQ_readout_refm::init_reg_mems();
	reg_mems reg_mems;
	reg_mems = new();
	reg_mems.init();
endtask

task EZQ_readout_refm::get_config_data();
    forever begin
        @(posedge `CLK);
        if(ram_data.exists(`RW_TEST)) begin
            rw_test = ram_data[`RW_TEST];
        end
        if(ram_data.exists(`INTR_MASK)) begin
            intr_mask = ram_data[`INTR_MASK];
        end
        if(ram_data.exists(`SYS_FUNC)) begin
            sys_func = ram_data[`SYS_FUNC];
        end
        if(ram_data.exists(`AWG_AMPLITUDE)) begin
            awg_amplitude = ram_data[`AWG_AMPLITUDE];
        end
        if(ram_data.exists(`AWG_FREQUENCY)) begin
            awg_frequency = ram_data[`AWG_FREQUENCY];
        end
        if(ram_data.exists(`AWG_PHASE)) begin
            awg_phase = ram_data[`AWG_PHASE];
        end
        if(ram_data.exists(`AWG_PUMP_CTRL)) begin
            awg_pump_ctrl = ram_data[`AWG_PUMP_CTRL];
        end
        if(ram_data.exists(`AWG_MARKER_CTRL)) begin
            awg_marker_en = ram_data[`AWG_MARKER_CTRL];
        end
        if(ram_data.exists(`DAQ_SEND_DATA)) begin
            daq_send_data = ram_data[`DAQ_SEND_DATA];
        end
        if(ram_data.exists(`DAQ_FREQUENCY)) begin
            daq_frequency = ram_data[`DAQ_FREQUENCY];
        end
        if(ram_data.exists(`DAQ_PHASE)) begin
            daq_phase = ram_data[`DAQ_PHASE];
        end
        if(ram_data.exists(`WAVE_SAMPLE_DEPTH)) begin
            wave_smaple_depth = ram_data[`WAVE_SAMPLE_DEPTH];
        end
        if(ram_data.exists(`DEMOD_WIN_WIDTH)) begin
            demod_win_width = ram_data[`DEMOD_WIN_WIDTH];
        end
        if(ram_data.exists(`READ_THRESHOLD)) begin
            read_threshold = ram_data[`READ_THRESHOLD];
        end
        if(ram_data.exists(`READ_REQ_CTRL)) begin
            read_req_ctrl = ram_data[`READ_REQ_CTRL];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q0)) begin
            demod_width_q0 = ram_data[`DEMOD_WIDTH_Q0];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q1)) begin
            demod_width_q1 = ram_data[`DEMOD_WIDTH_Q1];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q2)) begin
            demod_width_q2 = ram_data[`DEMOD_WIDTH_Q2];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q3)) begin
            demod_width_q3 = ram_data[`DEMOD_WIDTH_Q3];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q4)) begin
            demod_width_q4 = ram_data[`DEMOD_WIDTH_Q4];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q5)) begin
            demod_width_q5 = ram_data[`DEMOD_WIDTH_Q5];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q6)) begin
            demod_width_q6 = ram_data[`DEMOD_WIDTH_Q6];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q7)) begin
            demod_width_q7 = ram_data[`DEMOD_WIDTH_Q7];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q8)) begin
            demod_width_q8 = ram_data[`DEMOD_WIDTH_Q8];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q9)) begin
            demod_width_q9 = ram_data[`DEMOD_WIDTH_Q9];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q10)) begin
            demod_width_q10 = ram_data[`DEMOD_WIDTH_Q10];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q11)) begin
            demod_width_q11 = ram_data[`DEMOD_WIDTH_Q11];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q12)) begin
            demod_width_q12 = ram_data[`DEMOD_WIDTH_Q12];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q13)) begin
            demod_width_q13 = ram_data[`DEMOD_WIDTH_Q13];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q14)) begin
            demod_width_q14 = ram_data[`DEMOD_WIDTH_Q14];
        end
        if(ram_data.exists(`DEMOD_WIDTH_Q15)) begin
            demod_width_q15 = ram_data[`DEMOD_WIDTH_Q15];
        end
    end
endtask


task EZQ_readout_refm::mcu_process(bit[31:0] base_addr,ref bit[31:0] inst_ram[bit[31:0]],ref bit[31:0] mcu_reg[bit[31:0]],ref bit[31:0]ram_data[bit[31:0]],ref bit mcu_finish,ref mcu_cw_item mcu_cw_item_q[$]);
    bit                 feedback;
    bit [31:0]          mcu_addr;
    bit [31:0]          mcu_data;
    bit [6:0]           opcode;
    bit [2:0]           funct3;
    bit [6:0]           funct7;
    bit                 des_reg_wr;
    bit [4:0]           des_reg_addr;
    int                 des_reg_data;
    int                 des_reg_data_com;
    bit [4:0]           src_reg1_addr;
    bit [4:0]           src_reg2_addr;
    int                 src1_data;
    int                 src2_data;
    int                 src1_data_com;
    int                 src2_data_com;
    bit [31:0]          src1_data_unsigned;
    bit [31:0]          src2_data_unsigned;
    bit signed [11:0]   imm_data;
    bit signed [11:0]   imm_data_com;
    bit [11:0]          imm_data_unsigned;
    bit signed [11:0]   b_imm_data;
    bit signed [11:0]   b_imm_data_com;
    bit [11:0]          b_imm_data_unsigned;
    bit                 b_condition;
    bit signed [19:0]   u_imm_data;
    bit signed [20:0]   j_imm_data_21;
    bit signed [11:0]   j_imm_data_12;
    bit [63:0]          clock_cnt;
    mcu_cw_item            mcu_cw_item;
    bit                 ram_wr;
    bit [3:0]           ram_mask;
    bit [1:0]           ram_byte;
    bit [31:0]          wr_ram_data;
    bit signed [31:0]   imm_32;
    bit unsigned [31:0] imm_32_unsigned;
    bit signed [31:0]   imm_com_32;
    int                 inst_cnt;
    bit [31:0]          ram_addr;
    bit [31:0]          rd_ram_data;
    bit [1:0]           ram_offset;

    mcu_addr = base_addr;
    mcu_finish = 0;
    feedback = 0;
    clock_cnt = 3;
    `uvm_info(get_type_name(),"wait sync_in",UVM_LOW)
    wait (`SYNC_IN);
    `uvm_info(get_type_name(),"wait sync_in",UVM_LOW)
    forever begin
        if(inst_ram.exists(mcu_addr) && mcu_finish==0) begin
            inst_cnt++;
            `uvm_info(get_type_name(),$sformatf("mcu reference model is processing %0d th instruction",inst_cnt),UVM_LOW) 
            mcu_data = inst_ram[mcu_addr];
            `uvm_info(get_type_name(),$sformatf("mcu_addr=%0h,get mcu_data %0h",mcu_addr,mcu_data),UVM_LOW)
            opcode = mcu_data[6:0];
            des_reg_addr = mcu_data[11:7];
            funct3 = mcu_data[14:12];
            src_reg1_addr = mcu_data[19:15];
            src_reg2_addr = mcu_data[24:20]; 
            `uvm_info(get_type_name(),$sformatf("src_reg1_addr=%0h,src_reg2_addr=%0h",src_reg1_addr,src_reg2_addr),UVM_LOW)
            funct7 = mcu_data[31:25];
            if(opcode == 7'b0110011) begin              //R type  
                src1_data = mcu_reg.exists(src_reg1_addr) ? mcu_reg[src_reg1_addr] : 0;
                src2_data = mcu_reg.exists(src_reg2_addr) ? mcu_reg[src_reg2_addr] : 0;
                `uvm_info(get_type_name(),$sformatf("src1_data=%0h,src2_data=%0h",src1_data,src2_data),UVM_LOW)
                src1_data_com = (src1_data[31]==0) ? src1_data : {src1_data[31],~src1_data[30:0]} + 1'b1;
                src2_data_com = (src2_data[31]==0) ? src2_data : {src2_data[31],~src2_data[30:0]} + 1'b1;
                `uvm_info(get_type_name(),$sformatf("src1_data_com=%0h,src2_data_com=%0h",src1_data_com,src2_data_com),UVM_LOW)
                src1_data_unsigned = src1_data;
                src2_data_unsigned = src2_data;
                des_reg_wr = 1;
                if (funct7 == 7'b0000000) begin
                    if(funct3 == 3'b000) begin          // R add
                        `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type add",opcode),UVM_LOW)
                        des_reg_data = src1_data + src2_data;
                    end
                    else if(funct3 == 3'b001) begin     //R sll
                        des_reg_data = src1_data << src2_data[4:0];      
                        `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type sll",opcode),UVM_LOW)
                    end
                    else if (funct3 == 3'b010) begin    //R slt
                        des_reg_data = src1_data < src2_data ? 1 : 0;      
                        `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type slt",opcode),UVM_LOW)
                    end
                    else if (funct3 == 3'b011) begin    //R sltu (set less than unsigned)
                        des_reg_data = src1_data_unsigned < src2_data_unsigned ? 1 : 0;      
                        `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type sltu",opcode),UVM_LOW)
                    end
                    else if (funct3 == 3'b100) begin    //R xor
                        des_reg_data = src1_data ^ src2_data;      
                        `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type xor",opcode),UVM_LOW)
                    end
                    else if (funct3 == 3'b101) begin    //R srl
                        des_reg_data = src1_data >> src2_data[4:0];      
                        `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type srl",opcode),UVM_LOW)
                    end
                    else if (funct3 == 3'b110) begin    //R or
                        des_reg_data = src1_data | src2_data;      
                        `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type or",opcode),UVM_LOW)
                    end
                    else if (funct3 == 3'b111) begin    //R and
                        des_reg_data = src1_data & src2_data;      
                        `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type and",opcode),UVM_LOW)
                    end
                end
                else if (funct7 == 7'b0100000) begin
                    if(funct3 == 3'b000) begin          //R sub
                        des_reg_data = src1_data - src2_data;
                        `uvm_info(get_type_name(),$sformatf("des_reg_data_com=%0h,des_reg_data=%0h",des_reg_data,des_reg_data_com),UVM_LOW)
                        `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type sub",opcode),UVM_LOW)
                    end
                    else if(funct3==3'b101) begin       //R sra
                        des_reg_data = src1_data >>> src2_data[4:0];      
                        `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type sra",opcode),UVM_LOW)
                    end
                    else begin
                        des_reg_wr = 0;
                        `uvm_error(get_type_name(),$sformatf("R type opcode,funct7 is 7'b000000,but funct3(%b)is illegal",funct3))
                    end
                end
                else begin
                    des_reg_wr = 0;
                    `uvm_error(get_type_name(),$sformatf("R type opcode,funct7(%b)is illegal",funct7))
                end
                mcu_addr = mcu_addr+32'h4;
            end
            else if(opcode == 7'b0010011) begin         //I type
                des_reg_wr = 1;
                src1_data = mcu_reg.exists(src_reg1_addr) ? mcu_reg[src_reg1_addr] : 0;
                src1_data_com = (src1_data[31]==0) ? src1_data : {src1_data[31],~src1_data[30:0]} + 1'b1;
                imm_data = mcu_data[31:20];
                imm_32 = {{21{imm_data[11]}},imm_data[10:0]};
                imm_32_unsigned = imm_32;
                //imm_com_32 = (imm_32[31]==0) ? imm_32 : {imm_32[31],~imm_32[30:0]} + 1;
                src1_data_unsigned = src1_data;
                imm_data_unsigned = imm_data;
                `uvm_info(get_type_name(),$sformatf("src1_data = %0h,imm_data = %0h",src1_data,imm_data),UVM_LOW)
                `uvm_info(get_type_name(),$sformatf("src1_data_com = %0h,imm_32 = %0h,imm_com_32=%0h",src1_data_com,imm_32,imm_com_32),UVM_LOW)
                `uvm_info(get_type_name(),$sformatf("src1_data_unsigned = %0h,imm_data_unsigned = %0h",src1_data_unsigned,imm_data_unsigned),UVM_LOW)
                if(funct3 == 3'b000) begin              //I addi
                    des_reg_data = src1_data + imm_32;
                    `uvm_info(get_type_name(),$sformatf("des_reg_data_com = %0h,des_reg_data = %0h",des_reg_data_com,des_reg_data),UVM_LOW)
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type addi",opcode),UVM_LOW)
                end
                else if(funct3 == 3'b010) begin         //I slti
                    des_reg_data = src1_data < imm_32 ? 1 : 0;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type slti",opcode),UVM_LOW)
                end
                else if(funct3 == 3'b011) begin         //I sltiu(set less than imm unsigned)
                    des_reg_data = src1_data_unsigned < imm_32_unsigned ? 1 : 0;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type sltiu",opcode),UVM_LOW)
                end
                else if(funct3 == 3'b100) begin         //I xori
                    des_reg_data = src1_data ^ imm_32;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type xori",opcode),UVM_LOW)
                end
                else if(funct3 == 3'b110) begin         //I ori
                    des_reg_data = src1_data | imm_32;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type ori",opcode),UVM_LOW)
                end
                else if(funct3 == 3'b111) begin         //I andi
                    des_reg_data = src1_data & imm_32;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type andi",opcode),UVM_LOW)
                end
                else if(funct3 == 3'b001 && funct7 == 7'b0000000) begin     //slli
                    des_reg_data = src1_data << imm_data;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type slli",opcode),UVM_LOW)
                end
                else if(funct3 == 3'b101 && funct7 == 7'b0000000) begin     //srli
                    des_reg_data = src1_data >> imm_data;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type srli",opcode),UVM_LOW)
                end
                else if(funct3 == 3'b101 && funct7 == 7'b0100000) begin     //sali
                    des_reg_data = src1_data >>> imm_data;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type sali",opcode),UVM_LOW)
                end
                mcu_addr = mcu_addr+32'h4;
            end
            else if(opcode == 7'b0000011) begin         //I type
                des_reg_wr = 1;
                src1_data = mcu_reg.exists(src_reg1_addr) ? mcu_reg[src_reg1_addr] : 0;
                src1_data_com = {src1_data[31],~src1_data[30:0]} + 1'b1;
                imm_data = mcu_data[31:20];
                imm_data_com = {imm_data[11],~mcu_data[10:0]} + 1;
                imm_data_unsigned = imm_data;
                ram_addr = ((src1_data+imm_data)/4)*4;
                ram_offset = (src1_data+imm_data)%4;
                rd_ram_data = ram_data.exists(ram_addr) ? ram_data[ram_addr] : 0;
                `uvm_info(get_type_name(),$sformatf("src1_data = %h,imm_data = %0h",src1_data,imm_data),UVM_LOW)
                `uvm_info(get_type_name(),$sformatf("ram_addr=%0h,ram_data.exists = %h,rd_ram_data = %0h",ram_addr,ram_data.exists(ram_addr),rd_ram_data),UVM_LOW)
                if (funct3 == 3'b000) begin             //I lb
                    //des_reg_data =  {{25{rd_ram_data[7+ram_offset*8]}},rd_ram_data[6+ram_offset*8:0+ram_offset*8]};
                    if(ram_offset == 0) begin
                         des_reg_data =  {{25{rd_ram_data[7]}},rd_ram_data[6:0]};
                    end
                    else if(ram_offset == 1) begin
                         des_reg_data =  {{25{rd_ram_data[15]}},rd_ram_data[14:8]};
                    end
                    else if(ram_offset == 2) begin
                         des_reg_data =  {{25{rd_ram_data[23]}},rd_ram_data[22:16]};
                    end
                    else begin
                         des_reg_data =  {{25{rd_ram_data[31]}},rd_ram_data[30:24]};
                    end
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type lb",opcode),UVM_LOW)
                end
                else if (funct3 == 3'b001) begin        //I lh
                    des_reg_data[31:16] = 'h0;
                    if((src1_data+imm_data)%2 != 0) begin
                        `uvm_error(get_type_name(),$sformatf("instruction lh but read address(%0h) is illegal",src1_data+imm_data))
                    end
                    des_reg_data =  ram_offset == 0 ? {{17{rd_ram_data[15]}},rd_ram_data[14:0]} : {{17{rd_ram_data[31]}},rd_ram_data[30:16]};
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type lh",opcode),UVM_LOW)
                end
                else if (funct3 == 3'b010) begin        //I lw
                    if((src1_data+imm_data)%4 !=0 ) begin
                        `uvm_error(get_type_name(),$sformatf("instruction lw but read address(%0h) is illegal",src1_data+imm_data))
                    end
                    des_reg_data = rd_ram_data;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type lw",opcode),UVM_LOW)
                end
                else if (funct3 == 3'b100) begin        //I lbu
                    //des_reg_data =  {{25{rd_ram_data[7+ram_offset*8]}},rd_ram_data[6+ram_offset*8:0+ram_offset*8]};
                    if(ram_offset == 0) begin
                         des_reg_data =  rd_ram_data[7:0];
                    end
                    else if(ram_offset == 1) begin
                         des_reg_data =  rd_ram_data[15:8];
                    end
                    else if(ram_offset == 2) begin
                         des_reg_data =  rd_ram_data[23:16];
                    end
                    else begin
                         des_reg_data = rd_ram_data[31:24];
                    end
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type lbu",opcode),UVM_LOW)
                end
                else if (funct3 == 3'b101) begin        //I lhu
                    if((src1_data+imm_data)%2 !=0 ) begin
                        `uvm_error(get_type_name(),$sformatf("instruction lhu but read address(%0h) is illegal",src1_data+imm_data))
                    end
                    des_reg_data = ram_offset == 0 ? {16'h0,rd_ram_data[15:0]} : {16'h0,rd_ram_data[31:16]};
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type lhu",opcode),UVM_LOW)
                end
                else begin
                    `uvm_error(get_type_name(),$sformatf("I type opcode,funct3(%b)is illegal",funct3))
                end
                mcu_addr = mcu_addr+32'h4;
            end
            else if(opcode == 7'b0100011) begin         // S type
                imm_data = {mcu_data[31:25],mcu_data[11:7]};
                imm_data_com = {imm_data[11],~mcu_data[10:0]} + 1;
                imm_data_unsigned = imm_data;
                src1_data = mcu_reg.exists(src_reg1_addr) ? mcu_reg[src_reg1_addr] : 0;
                src2_data = mcu_reg.exists(src_reg2_addr) ? mcu_reg[src_reg2_addr] : 0;
                `uvm_info(get_type_name(),$sformatf("src1_data=%0h,src2_data=%0h",src1_data,src2_data),UVM_LOW)
                src1_data_com = {src1_data[31],~src1_data[30:0]} + 1'b1;
                src2_data_com = {src2_data[31],~src2_data[30:0]} + 1'b1;
                src1_data_unsigned = src1_data;
                src2_data_unsigned = src2_data;
                if(funct3 == 3'b000) begin              //S sb
                    ram_data[src1_data+imm_data][31:8] = ram_data.exists(src1_data+imm_data) ? ram_data[src1_data+imm_data][31:8] : 24'h0;
                    ram_data[src1_data+imm_data][7:0] = src2_data[7:0];
                    ram_byte = (src1_data + imm_data)%4;
                    ram_wr = 1;
                    wr_ram_data = {4{src2_data[7:0]}};
                    ram_mask = 4'b0000;
                    ram_mask[ram_byte] = 1'b1;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type sb",opcode),UVM_LOW)
                end
                else if(funct3 == 3'b001) begin         //S sh
                    ram_data[src1_data+imm_data][31:16] = ram_data.exists(src1_data+imm_data) ? ram_data[src1_data+imm_data][31:16] : 16'h0;
                    ram_data[src1_data+imm_data][15:0] = src2_data[15:0];
                    ram_byte = (src1_data + imm_data)%4;
                    ram_wr = 1;
                    wr_ram_data = {2{src2_data[15:0]}};
                    if (ram_byte == 0 || ram_byte ==2) begin
                        ram_mask = (ram_byte == 0) ? 4'b0011 : 4'b1100;
                    end
                    else begin
                        ram_mask = 0;
                        `uvm_error(get_type_name(),$sformatf("instruction sh,but write address(%0h) is illegal",src1_data+imm_data))
                    end
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type sh",opcode),UVM_LOW)
                end
                else if(funct3 == 3'b010) begin         //S sw
                    ram_data[src1_data+imm_data] = src2_data;
                    ram_wr = 1;
                    wr_ram_data = src2_data;
                    ram_mask = 4'b1111;
                    if((src1_data+imm_data)%4!=0) begin
                        `uvm_error(get_type_name(),$sformatf("instruction sw but write address(%0h) is illegal",src1_data+imm_data))
                    end
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type sw",opcode),UVM_LOW)
                end
                else begin
                    ram_wr = 0;
                    wr_ram_data = 0;
                    ram_mask = 0;
                    `uvm_error(get_type_name(),$sformatf("S type opcode,funct3(%b)is illegal",funct3))
                end
                mcu_addr = mcu_addr+32'h4;
                if(ram_wr==1) begin
                    ram_wr = 0;
                    mcu_cw_item = new();
                    mcu_cw_item.clock_cycle = clock_cnt + 1;
                    mcu_cw_item.cw_data = 0;
                    mcu_cw_item.wr_ram = 1;
                    mcu_cw_item.wr_ram_addr = src1_data+imm_data;
                    mcu_cw_item.wr_ram_data = wr_ram_data;
                    mcu_cw_item.wr_ram_mask = ram_mask;
                    mcu_cw_item.wr_reg = 0;
                    mcu_cw_item.wr_reg_addr = 0;
                    mcu_cw_item.wr_reg_data = 0;
                    `uvm_info(get_type_name(),"mcu_rm send mcu_cw_item to scoreboard",UVM_LOW)
                    mcu_cw_item.print();
                    mcu_cw_item_q.push_back(mcu_cw_item);
                end
            end
            else if(opcode == 7'b1100011) begin         //B type
                src1_data = mcu_reg.exists(src_reg1_addr) ? mcu_reg[src_reg1_addr] : 0;
                src2_data = mcu_reg.exists(src_reg2_addr) ? mcu_reg[src_reg2_addr] : 0;
                src1_data_unsigned = src1_data;
                src2_data_unsigned = src2_data;
                `uvm_info(get_type_name(),$sformatf("src1_data=%0h,src2_data=%0h",src1_data,src2_data),UVM_LOW)
                b_imm_data = {mcu_data[31],mcu_data[7],mcu_data[30:25],mcu_data[11:8],1'b0};
                if(funct3 == 3'b000) begin              //B beq
                    b_condition = (src1_data == src2_data) ? 1 : 0;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type beq",opcode),UVM_LOW)
                end
                else if(funct3 == 3'b001) begin         //B bne
                    b_condition = (src1_data != src2_data) ? 1 : 0;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type bne",opcode),UVM_LOW)
                end
                else if(funct3 == 3'b100) begin         //B blt
                    b_condition = (src1_data < src2_data) ? 1 : 0;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type blt",opcode),UVM_LOW)
                end
                else if(funct3 == 3'b101) begin         //B bge
                    b_condition = (src1_data >= src2_data) ? 1 : 0;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type bge",opcode),UVM_LOW)
                end
                else if(funct3 == 3'b110) begin         //B bltu
                    b_condition = (src1_data_unsigned < src2_data_unsigned) ? 1 : 0;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type bltu",opcode),UVM_LOW)
                end
                else if(funct3 == 3'b111) begin         //B bgeu
                    b_condition = (src1_data_unsigned >= src2_data_unsigned) ? 1 : 0;
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type bgeu",opcode),UVM_LOW)
                end
                else begin
                    `uvm_error(get_type_name(),$sformatf("B type opcode,funct3(%0b) is illegal",funct3))
                end
                if(b_condition == 1) begin    
                    mcu_addr = mcu_addr + b_imm_data;
                    b_condition = 0;
                end
                else begin
                    mcu_addr = mcu_addr + 32'h4;
                end
            end
            else if(opcode == 7'b0110111) begin         //U type lui
                `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type lui",opcode),UVM_LOW)
                u_imm_data = mcu_data[31:12];
                des_reg_wr = 1;
                des_reg_data = {u_imm_data,12'h0};   
                mcu_addr = mcu_addr + 32'h4;
            end
            else if(opcode == 7'b0010111) begin         //U type auipc
                `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type auipc",opcode),UVM_LOW)
                u_imm_data = mcu_data[31:12];
                des_reg_wr = 1;
                des_reg_data = mcu_addr + {u_imm_data,12'h0};
                mcu_addr = mcu_addr + 32'h4;
            end 
            else if(opcode == 7'b1101111) begin        //J type jal
                `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type jal",opcode),UVM_LOW)
                j_imm_data_21 = {mcu_data[31],mcu_data[19:12],mcu_data[20],mcu_data[30:21],1'b0};
                `uvm_info(get_type_name(),$sformatf("mcu_data = %h,j_imm_data_21 = %0h",mcu_data,j_imm_data_21),UVM_LOW)
                des_reg_wr = 1;
                des_reg_data = mcu_addr +32'h4;
                mcu_addr = mcu_addr + j_imm_data_21; 
            end
            else if(opcode == 7'b1100111) begin        //J type jalr
                `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type jalr",opcode),UVM_LOW)
                src1_data = mcu_reg.exists(src_reg1_addr) ? mcu_reg[src_reg1_addr] : 0;
                j_imm_data_12 = mcu_data[31:20];
                des_reg_wr = 1;
                des_reg_data = mcu_addr + 32'h4;
                mcu_addr = src1_data + j_imm_data_12;
            end 
            else if(opcode == 7'b0001011) begin        
                src1_data = mcu_reg.exists(src_reg1_addr) ? mcu_reg[src_reg1_addr] : 0;
                src1_data_com = (src1_data[31]==0) ? src1_data : {src1_data[31],~src1_data[30:0]} + 1'b1;
                imm_data = mcu_data[31:20];
                imm_32 = {{21{imm_data[11]}},imm_data[10:0]};
                //imm_data_com = {imm_data[11],~mcu_data[10:0]} + 1;
                `uvm_info(get_type_name(),$sformatf("src_reg1_addr=%0h,src1_data=%0h,imm_data=%0h,imm_32=%0h",src_reg1_addr,src1_data,imm_data,imm_32),UVM_LOW)
                if(funct3 == 3'b000) begin              //WAIT
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type wait",opcode),UVM_LOW)
                    clock_cnt = clock_cnt + src1_data + imm_32;
                    des_reg_data = src1_data + imm_32;
                    des_reg_wr = 1;
                    `uvm_info(get_type_name(),$sformatf("wait %0d cycle,clock_cnt=%0d",src1_data+imm_32,clock_cnt),UVM_LOW)
                end
                else if(funct3 == 3'b010) begin         //SEND
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type send",opcode),UVM_LOW)
                    mcu_cw_item = new();
                    mcu_cw_item.clock_cycle = clock_cnt+1; 
                    `uvm_info(get_type_name(),$sformatf("clock_cnt=%0d",clock_cnt),UVM_LOW)
                    des_reg_data = src1_data + imm_32;
                    des_reg_wr = 1;
                    mcu_cw_item.cw_data = src1_data + imm_32; 
                    `uvm_info(get_type_name(),"mcu_rm send mcu_cw_item to scoreboard",UVM_LOW)
                    mcu_cw_item.print();
                    mcu_cw_item_q.push_back(mcu_cw_item);
                end
                else if(funct3 == 3'b011) begin         //SENDC
                    `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type sendc",opcode),UVM_LOW)
                    mcu_cw_item = new();
                    mcu_cw_item.clock_cycle = clock_cnt+1; 
                    des_reg_data = src1_data + imm_32 + feedback;  
                    des_reg_wr = 1;
                    mcu_cw_item.cw_data = src1_data + imm_32 + feedback;  
                    `uvm_info(get_type_name(),"mcu_rm send mcu_cw_item to scoreboard",UVM_LOW)
                    mcu_cw_item.print();
                    mcu_cw_item_q.push_back(mcu_cw_item);
                end
                mcu_addr = mcu_addr + 32'h4;
            end
            else if(opcode == 7'b0101011 && mcu_data[31:7]==25'h0) begin    //EXIT
                `uvm_info(get_type_name(),$sformatf("mcu opcode = %b,instruction is type exit",opcode),UVM_LOW)
                mcu_finish = 1;
                clock_cnt = 0;
            end
            if(des_reg_wr == 1 && des_reg_addr!=0) begin
                mcu_cw_item = new();
                mcu_cw_item.clock_cycle = clock_cnt + 2;
                mcu_cw_item.cw_data = 0;
                mcu_cw_item.wr_ram = 0;
                mcu_cw_item.wr_ram_addr = 0;
                mcu_cw_item.wr_ram_data = 0;
                mcu_cw_item.wr_reg = 1;
                mcu_cw_item.wr_reg_addr = des_reg_addr;
                mcu_cw_item.wr_reg_data = des_reg_data;
                `uvm_info(get_type_name(),"mcu_rm send mcu_cw_item to scoreboard",UVM_LOW)
                mcu_cw_item.print();
                mcu_cw_item_q.push_back(mcu_cw_item);
                mcu_reg[des_reg_addr] = des_reg_data;
                des_reg_wr = 0;
            end
            clock_cnt = clock_cnt + 3; 
            //`uvm_info(get_type_name(),$sformatf("clock_cnt=%0d",clock_cnt),UVM_LOW)
            @(posedge `CLK);
        end
        else begin
            @(posedge `CLK);
            mcu_finish = 1;
            clock_cnt = 0;
        end
    end    
endtask





task EZQ_readout_refm::send_awg_codeword();
    mcu_cw_item mcu_cw_item;
    forever begin
        if(awg_mcu_cw_item_q.size()>0) begin
            mcu_cw_item = awg_mcu_cw_item_q.pop_front();
            `uvm_info(get_type_name(),"awg send mcu_cw_item",UVM_LOW)
            mcu_cw_item.print();
            mcu_2awgrm_port.write(mcu_cw_item);
        end
        @(posedge `CLK);
    end
endtask
        
task EZQ_readout_refm::send_daq_codeword();
    mcu_cw_item mcu_cw_item;
    forever begin
        if(daq_mcu_cw_item_q.size()>0) begin
            mcu_cw_item = daq_mcu_cw_item_q.pop_front();
            `uvm_info(get_type_name(),"daq send mcu_cw_item",UVM_LOW)
            mcu_cw_item.print();
            mcu_2daqrm_port.write(mcu_cw_item);
        end
        @(posedge `CLK);
    end
endtask

task EZQ_readout_refm::run_phase(uvm_phase phase);
    fork
        get_spi_item();
        get_config_data();
        mcu_process(32'h700000,ram_data,awg_mcu_reg,ram_data,awg_mcu_finish,awg_mcu_cw_item_q);
        mcu_process(32'h200000,ram_data,daq_mcu_reg,ram_data,daq_mcu_finish,daq_mcu_cw_item_q);

        send_awg_codeword();
        send_daq_codeword();
    join_none
    wait(awg_mcu_finish && daq_mcu_finish);
    disable fork;

endtask : run_phase

`endif //EZQ_READOUT_REFM