162 lines
3.5 KiB
Systemverilog
162 lines
3.5 KiB
Systemverilog
class spi_driver;
|
|
|
|
static bit my_cmd=1'b0;
|
|
static bit[24:0] last_addr;
|
|
static bit last_s;
|
|
|
|
//MOSI data pkt, other input_signals are not packed
|
|
spi_trans m_trans;
|
|
|
|
//interface
|
|
virtual spi_if vif;
|
|
|
|
//MOSI data_stream input to SPI(DUT)
|
|
bit stream[$];
|
|
|
|
//parameter for randomization
|
|
int pktnum;
|
|
int interval;
|
|
rand int error_time;
|
|
int half_sclk;
|
|
bit autarchy;
|
|
|
|
|
|
|
|
constraint cstr{
|
|
error_time <= 544;
|
|
error_time >= -544;
|
|
}
|
|
|
|
function new();
|
|
endfunction
|
|
extern task do_drive();
|
|
extern task make_pkt(spi_trans tr);
|
|
|
|
endclass : spi_driver
|
|
|
|
|
|
task spi_driver::do_drive();
|
|
|
|
$display("pkt_num:\t%0d",pktnum);
|
|
|
|
while(!vif.rstn) begin
|
|
vif.csn = 1'b1;
|
|
vif.sclk = 1'b1;
|
|
@(posedge vif.clk);
|
|
end
|
|
|
|
while(pktnum>0) begin
|
|
|
|
//$display(my_cmd);
|
|
make_pkt(m_trans);
|
|
|
|
repeat(interval)
|
|
@(posedge vif.clk);
|
|
|
|
pktnum--;
|
|
end
|
|
|
|
endtask : do_drive
|
|
|
|
|
|
task spi_driver::make_pkt(spi_trans tr);
|
|
int i=0,j=0;
|
|
int cs_time,mo_time;
|
|
|
|
|
|
//**********************Create and Randomize a pkt**********************//
|
|
tr = new();
|
|
|
|
if(!tr.randomize() with {
|
|
cmd==my_cmd;
|
|
(cmd==1'b0 || s==last_s);
|
|
(cmd==1'b0 || addr==last_addr);
|
|
addr[24:20] == 5'b00000 ||
|
|
addr[24:20] == 5'b00001 ||
|
|
addr[24:20] == 5'b00010;
|
|
})
|
|
$fatal(0,"Randomize Failed");
|
|
|
|
if(tr.cmd == 1'b0) begin
|
|
last_addr = tr.addr;
|
|
last_s = tr.s;
|
|
end
|
|
|
|
my_cmd = ~my_cmd;
|
|
|
|
|
|
//Autarchy: Testcase force to assign some params
|
|
interval = tr.interval;
|
|
if(!autarchy) begin
|
|
half_sclk = tr.half_sclk;
|
|
end
|
|
|
|
|
|
//*****************initialize chip_select and input_clk******************//
|
|
vif.csn <= 1'b1;
|
|
vif.sclk <= 1'b1;
|
|
vif.mosi <= stream[0];
|
|
@(posedge vif.clk);
|
|
vif.csn <= 1'b0;
|
|
vif.sclk <= 1'b1;
|
|
|
|
//unpack into bitstream
|
|
stream.delete();
|
|
tr.unpack(stream);
|
|
|
|
//mosi valid time: time for bitstream to be all sent
|
|
//csn valid_time: maybe a delay after or ahead of mosi_finished
|
|
mo_time = (stream.size())*2*half_sclk;
|
|
cs_time = (pktnum==1) ? (mo_time + error_time%mo_time) : mo_time;
|
|
|
|
$display("***************************ONE PKT DRIVERED***************************");
|
|
$display("half_sclk:\t%0d\t\t\t\t\t\t **",half_sclk);
|
|
$display("interval:\t%0d\t\t\t\t\t\t **",interval);
|
|
//$display("error_time:\t%0d\t\t\t\t\t\t **",error_time);
|
|
//$display("data_size:\t%0d\t\t\t\t\t\t **",tr.data.size());
|
|
//$display("cmd:\t\t%0d\t\t\t\t\t\t **",tr.cmd);
|
|
//$display(stream);
|
|
if(!tr.cmd)
|
|
for(i=0;i<tr.data.size;i++)
|
|
$display("mosi:\t\t%32b\t\t **",tr.data[i]);
|
|
|
|
//********************drive the stream onto interface********************//
|
|
fork
|
|
|
|
|
|
//************************Make sclk************************//
|
|
begin
|
|
for(j=0;j<cs_time;j++) begin
|
|
if(j % half_sclk == 0 && j!=0)
|
|
vif.sclk <= ~vif.sclk;
|
|
@(posedge vif.clk);
|
|
end
|
|
vif.sclk = 1'b1;
|
|
@(posedge vif.clk);
|
|
vif.csn = 1'b1;
|
|
end
|
|
|
|
//************************Send data************************//
|
|
begin
|
|
for(i=0;i<mo_time;i++) begin
|
|
|
|
//send data:
|
|
// data will be sampled at posedge,
|
|
// so prepare them at the negedge before each posedge
|
|
if(i % (2*half_sclk) == half_sclk)begin
|
|
vif.mosi <= stream[(i/half_sclk-1)/2];
|
|
//$display(i);
|
|
end
|
|
@(posedge vif.clk);
|
|
|
|
end
|
|
end
|
|
|
|
|
|
join
|
|
|
|
$display("**********************************************************************");
|
|
|
|
endtask
|
|
|