lin-win-share/DA4008_V1.3/model/SPI_DRIVER.sv

425 lines
10 KiB
Systemverilog

//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;i<data.size();i++)begin
if(data[i] != rhs_.data[i])
result = 1'b0;
end
end
return result;
endfunction : compare
function void spi_item::print();
int i=0;
if(!cmd)$display("----------ONE-PKT-DRIVING----------");
else $display("---------ONE-PKT-COLLECTING--------");
$display("cmd:\t%h",cmd);
$display("addr:\t%h",addr);
$display("cfgid:\t%h",cfgid);
for(i=0;i<data.size();i++)begin
$display("data[%2d]='h%h",i,data[i]);
end
$display("-----------------------------------");
endfunction : print
function void spi_item::unpack(ref bit stream[$]);
int i=0,j=0;
stream[0]=cmd;
for(i=0;i<25;i++)
stream[i+1] = addr[24-i];
for(i=0;i<5;i++)
stream[i+26]= cfgid[4-i];
stream[31]=0;
for(i=0;i<data.size();i++)begin
//$display("i=%2d,datai=%b",i,data[i]);
for(j=0;j<32;j++)begin
stream[32+i*32+j]=data[i][31-j];
//$display("i=%2d,j=%2d,streamij=%b",i,j,stream[32+i*32+j]);
end
end
endfunction
function void spi_item::fprint(integer fid);
int i=0;
if(!cmd)$fwrite(fid,"----------ONE-PKT-DRIVING----------\n");
else $fwrite(fid,"---------ONE-PKT-COLLECTING--------\n");
$fwrite(fid,"cmd:\t%h\n",cmd);
$fwrite(fid,"addr:\t%h\n",addr);
$fwrite(fid,"length:\t%d\n",data.size());
for(i=0;i<data.size();i++)begin
$fwrite(fid,"%h\n",data[i]);
end
$fwrite(fid,"-----------------------------------\n");
endfunction : fprint
function void spi_item::trprint(integer fid, ref int cmd_head[$]);
int i=0;
$fwrite(fid,"---------ONE-PKT-COLLECTING--------\n");
$fwrite(fid,"%h\n",cmd_head.pop_front());
$fwrite(fid,"%h\n",cmd_head.pop_front());
for(i=0;i<data.size();i++)begin
$fwrite(fid,"%h\n",data[i]);
end
$fwrite(fid,"-----------------------------------\n");
endfunction : trprint
function void spi_item::pack(bit stream[$]);
int i=0;
bit[31:0] data_temp=32'b0;
//$display(stream);
cmd = stream.pop_front();
for(i=0;i<25;i++)
addr[24-i] = stream.pop_front();
for(i=0;i<5;i++)
cfgid[4-i] = stream.pop_front();
//reserved
stream.pop_front();
data.delete();
while(stream.size()>0)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<cs_time;j++) begin
if(j%hs==0 && j!=0)
itf.sclk <= ~itf.sclk;
@(posedge itf.clk);
//$display("j = %0d", j);
end
itf.sclk = 1'b1;
repeat(4) @(posedge itf.clk);
itf.csn = 1'b1;
end
//Send data(at negedge)
begin
for(i=0;i<=cs_time;i++) begin
// Drive at negedge
if(i%(2*hs)==hs) begin
itf.mosi <= drv_stream[(i/hs-1)/2];
end
// Collect at posedge
else if(i%(2*hs)==0 && i!=0) begin
clt_stream.push_back(pkt.cmd ? itf.miso : itf.mosi);
//$write(itf.mosi);
end
@(posedge itf.clk);
end
//clt_stream collect the read_data/write_data, and
//the first 32bit should be consistent to the input command word
for(i=0;i<32;i++) clt_stream[i]=drv_stream[i];
//$display(clt_stream);
//$display("i = %0d", i);
pkt.pack(clt_stream);
end
join
//interval between two pkt send operation
repeat(pkt.interval-1)
@(posedge itf.clk);
endtask