SPI_Test/tb/testbench/spi_tb/spi_driver.sv

162 lines
3.5 KiB
Systemverilog
Raw Normal View History

2024-06-25 16:41:01 +08:00
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