425 lines
10 KiB
Systemverilog
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
|
||
|
|
|
||
|
|
|