//top-class : spi_driver //parameter : file_path: the path of *.txt file // itf: spi interface (type==spi_if) // half_sclk(option): =(half period of sclk)/(period of clk), default 5 // interval(option): the time to wait between the adjacent W/R operation/(period of clk), defaut 10 //example case : /* spi_driver my_drv; initial begin my_drv = new(); my_drv.file_path = "./../cfgdata/enveindex/wave_index_13.txt"; my_drv.itf = my_if; my_drv.half_sclk = 10; my_drv.interval = 50; my_drv.do_drive(); end//*/ class BinaryDataReader; // data_stream bit spi_data_queue[$]; int cmd_head[$]; // open & read txt_file function void read_txt_file(input string filename); int file_id; string line; bit [31:0] value; int i; //int cmd_head[$]; int length; bit cmd; int cnt; // open file_id = $fopen(filename, "r"); if (file_id == 0) begin $display("Error: Failed to open file %s", filename); return; end cnt = 0; // read while (!$feof(file_id)) begin //if ($fgets(line, file_id)) begin $fscanf(file_id,"%h\n",value); //$display("\nvalue = %h",value); //$display("cnt = %h",cnt); if(cnt == 0) begin cmd = value[31]; if(cmd) cmd_head.push_back(value); cnt ++; end else if(cnt == 1) begin if(cmd) cmd_head.push_back(value); length = value[15:0] / 4; if(!cmd) cnt ++; else cnt = 0; end else if((cnt == length-1 +2) | cmd) begin cnt = 0; end else begin cnt ++; end //$display("cmd = %h",cmd); //$display("length = %h",length); //$display(cmd_head); for (i = 31; i >= 0; i--) begin spi_data_queue.push_back(value[i]); end //end end // close $fclose(file_id); endfunction function void get_data_queue(ref bit data_queue[$]); data_queue = spi_data_queue; spi_data_queue.delete(); endfunction endclass //---------------------------------------------------------------------- class spi_item; //Properties for Randomizing the MOSI rand bit cmd; rand bit[24:0] addr; rand bit[ 4:0] cfgid; rand bit[31:0] data[$]; //Properties for Randomizing the pkt_sent process rand int interval; rand int half_sclk; constraint cstr { interval <= 1000; half_sclk >= 5; data.size >= 1; data.size <= 10000; } function new(string name="spi_item"); endfunction : new extern function bit compare(spi_item rhs_); extern function void print(); extern function void fprint(integer fid); extern function void trprint(integer fid, ref int cmd_head[$]); extern function void unpack(ref bit stream[$]); extern function void pack(bit stream[$]); extern function void adapt( ref bit stream[$] , int half_sclk , int interval ); endclass : spi_item function bit spi_item::compare(spi_item rhs_); bit result=1'b1; int i=0; if(this.data.size() != rhs_.data.size()) begin $display("data_sizes are different"); result = 1'b0; end else begin for(i=0;i0)begin for(i=0;i<32;i++) data_temp[31-i] = stream.pop_front(); data.push_back(data_temp); end endfunction function void spi_item::adapt(ref bit stream[$], int half_sclk, int interval); int i=0; bit[31:0] data_length=32'b0; bit[31:0] data_temp=32'b0; cmd = stream.pop_front(); //reserved stream.pop_front(); for(i=0;i<5;i++) cfgid[4-i] = stream.pop_front(); for(i=0;i<25;i++) addr[24-i] = stream.pop_front(); for(i=0;i<32;i++) data_length[31-i] = stream.pop_front(); data_length = {14'b0,data_length[19:2]}; repeat(data_length) begin for(i=0;i<32;i++) data_temp[31-i] = cmd ? 1'b0 : stream.pop_front(); data.push_back(data_temp); end this.half_sclk = half_sclk; this.interval = interval; endfunction //----------------------------------------------------------------- class spi_driver; string file_path; virtual spi_if itf; int interval = 10; int half_sclk = 5 ; spi_item m_trans; /*static string file_list[$]={ "./../cfgdata/instrmem/awg_inst.txt" //0 ,"./../cfgdata/instrmem/LongFlattop_bin.txt" //1 ,"./../cfgdata/instrmem/LongFlattopAmpAdj_bin.txt" //2 ,"./../cfgdata/instrmem/LongRectangle_bin.txt" //3 ,"./../cfgdata/instrmem/LongRectangle50us_bin.txt" //4 ,"./../cfgdata/instrmem/SingleWaveACCZ_bin.txt" //5 ,"./../cfgdata/instrmem/SingleWaveCombine_bin.txt" //6 ,"./../cfgdata/instrmem/SingleWaveCosine_bin.txt" //7 ,"./../cfgdata/instrmem/SingleWaveFlattop_bin.txt" //8 ,"./../cfgdata/instrmem/SingleWaveRectangle_bin.txt" //9 ,"./../cfgdata/instrmem/WaveHold_bin.txt" //10 ,"./../cfgdata/instrmem/Condition_bin.txt" //11 ,"./../cfgdata/instrmem/RabiFreqAmp_bin.txt" //12 ,"./../cfgdata/instrmem/WaveHoldSingle_bin.txt" //13 ,"./../cfgdata/instrmem/Cosine9_bin.txt" //14 //,"./../cfgdata/datamem/data_mem.txt" //15 ,"./../cfgdata/datamem/Cosine9_data_bin.txt" //15 //,"./../cfgdata/enveindex/enve_index.txt" //16 ,"./../cfgdata/enveindex/wave_index_13.txt" //16 //,"./../cfgdata/envemem/envelop_mem.txt" //17 ,"./../cfgdata/envemem/wave_bin_13.txt" //17 ,"./../cfgdata/envemem/rwave_bin_12.txt" //18 };//*/ function new(string name = "spi_seq"); endfunction : new extern task send(ref spi_item pkt); task do_drive(integer o_file_path=0); BinaryDataReader reader = new(); //spi_item m_trans; bit stream[$]; reader.read_txt_file(file_path); reader.get_data_queue(stream); //$display(stream); while(stream.size()>0) begin //$display(stream.size()); m_trans = new("m_trans"); m_trans.adapt(stream,half_sclk,interval); //m_trans.print(); send(m_trans); m_trans.print(); if(o_file_path!=0) begin //m_trans.fprint(o_file_path); if(m_trans.cmd) begin m_trans.trprint(o_file_path, reader.cmd_head); end end end endtask : do_drive endclass : spi_driver task spi_driver::send(ref spi_item pkt); bit drv_stream[$]; bit clt_stream[$]; int i=0,j=0; int cs_time; int hs = pkt.half_sclk; while(!itf.rstn) begin itf.csn = 1'b1; itf.sclk = 1'b1; @(posedge itf.clk); end //$display("unpacking"); //unpack into bitstream pkt.unpack(drv_stream); //$display(stream); //$display("unpackend"); //initialize chip_select and input_clk itf.csn <= 1'b1; itf.sclk <= 1'b1; itf.mosi <= drv_stream[0]; itf.cfgid <= pkt.cfgid; @(posedge itf.clk); itf.csn <= 1'b0; itf.sclk <= 1'b1; //$display("initialize end"); //csn valid time: time for bitstream to be all sent cs_time = drv_stream.size()*2*hs; //$display(stream.size()); //$display("drv_stream.size = %0d", drv_stream.size()); //$display(cs_time); //drive the stream onto interface fork //Make sclk begin for(j=0;j