//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
//// ////
|
//// ////
|
//// Copyright (C) 2017 Authors and OPENCORES.ORG ////
|
//// Copyright (C) 2017 Authors and OPENCORES.ORG ////
|
//// ////
|
//// ////
|
//// This source file may be used and distributed without ////
|
//// This source file may be used and distributed without ////
|
//// restriction provided that this copyright statement is not ////
|
//// restriction provided that this copyright statement is not ////
|
//// removed from the file and that any derivative work contains ////
|
//// removed from the file and that any derivative work contains ////
|
//// the original copyright notice and the associated disclaimer. ////
|
//// the original copyright notice and the associated disclaimer. ////
|
//// ////
|
//// ////
|
//// This source file is free software; you can redistribute it ////
|
//// This source file is free software; you can redistribute it ////
|
//// and/or modify it under the terms of the GNU Lesser General ////
|
//// and/or modify it under the terms of the GNU Lesser General ////
|
//// Public License as published by the Free Software Foundation; ////
|
//// Public License as published by the Free Software Foundation; ////
|
//// either version 2.1 of the License, or (at your option) any ////
|
//// either version 2.1 of the License, or (at your option) any ////
|
//// later version. ////
|
//// later version. ////
|
//// ////
|
//// ////
|
//// This source is distributed in the hope that it will be ////
|
//// This source is distributed in the hope that it will be ////
|
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
|
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
|
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
|
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
|
//// PURPOSE. See the GNU Lesser General Public License for more ////
|
//// PURPOSE. See the GNU Lesser General Public License for more ////
|
//// details. ////
|
//// details. ////
|
//// ////
|
//// ////
|
//// You should have received a copy of the GNU Lesser General ////
|
//// You should have received a copy of the GNU Lesser General ////
|
//// Public License along with this source; if not, download it ////
|
//// Public License along with this source; if not, download it ////
|
//// from http://www.opencores.org/lgpl.shtml ////
|
//// from http://www.opencores.org/lgpl.shtml ////
|
//// ////
|
//// ////
|
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
package riffa_bfm_class_pkg;
|
package riffa_bfm_class_pkg;
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
//
|
//
|
import q_pkg::*;
|
import q_pkg::*;
|
|
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
//
|
//
|
class riffa_transaction_class #(N);
|
class riffa_transaction_class #(N);
|
|
|
rand logic [31:0] len;
|
rand logic [31:0] len;
|
rand logic [30:0] off;
|
rand logic [30:0] off;
|
rand logic last;
|
rand logic last;
|
rand logic [(8*N)-1:0] data[];
|
rand logic [(8*N)-1:0] data[];
|
|
|
|
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
//
|
//
|
function int get_data_size(int len);
|
function int get_data_size(int len);
|
// int words = $ceil(len/(N/4)); // need to fix
|
// int words = $ceil(len/(N/4)); // need to fix
|
int words = len/(N/4);
|
int words = len/(N/4);
|
// $display("^^^ %16.t | words = %d", $time, words);
|
// $display("^^^ %16.t | words = %d", $time, words);
|
return(words);
|
return(words);
|
endfunction: get_data_size
|
endfunction: get_data_size
|
|
|
|
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
//
|
//
|
function void constant(int len, int off, bit last, logic [(8*N)-1:0] value);
|
function void constant(int len, int off, bit last, logic [(8*N)-1:0] value);
|
this.data = new[get_data_size(len)];
|
this.data = new[get_data_size(len)];
|
this.len = len;
|
this.len = len;
|
this.off = off;
|
this.off = off;
|
this.last = last;
|
this.last = last;
|
foreach(this.data[i])
|
foreach(this.data[i])
|
this.data[i] = value;
|
this.data[i] = value;
|
endfunction: constant
|
endfunction: constant
|
|
|
|
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
//
|
//
|
function void counting(int len, int off, bit last);
|
function void counting(int len, int off, bit last);
|
this.data = new[get_data_size(len)];
|
this.data = new[get_data_size(len)];
|
this.len = len;
|
this.len = len;
|
this.off = off;
|
this.off = off;
|
this.last = last;
|
this.last = last;
|
foreach(this.data[i])
|
foreach(this.data[i])
|
this.data[i] = i;
|
this.data[i] = i;
|
endfunction: counting
|
endfunction: counting
|
|
|
|
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
//
|
//
|
function void random(int len, int off, bit last);
|
function void random(int len, int off, bit last);
|
this.data = new[get_data_size(len)];
|
this.data = new[get_data_size(len)];
|
assert(this.randomize() with
|
assert(this.randomize() with
|
{
|
{
|
this.len == len; // why not working?
|
this.len == len; // why not working?
|
this.off == off;
|
this.off == off;
|
this.last == last;
|
this.last == last;
|
});
|
});
|
this.len = len;
|
this.len = len;
|
this.off = off;
|
this.off = off;
|
this.last = last;
|
this.last = last;
|
endfunction: random
|
endfunction: random
|
|
|
|
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
//
|
//
|
function void compare(riffa_transaction_class #(N) to, int max_mismatches = 8);
|
function void compare(riffa_transaction_class #(N) to, int max_mismatches = 8);
|
int error_count = 0;
|
int error_count = 0;
|
$display("!!! %16.t | %m", $time);
|
$display("!!! %16.t | %m", $time);
|
if(this.len != to.len)
|
if(this.len != to.len)
|
$display("!!! %16.t | ERROR! len mismatch", $time);
|
$display("!!! %16.t | ERROR! len mismatch", $time);
|
|
|
if(this.off != to.off)
|
if(this.off != to.off)
|
$display("!!! %16.t | ERROR! off mismatch", $time);
|
$display("!!! %16.t | ERROR! off mismatch", $time);
|
|
|
if(this.last != to.last)
|
if(this.last != to.last)
|
$display("!!! %16.t | ERROR! last mismatch", $time);
|
$display("!!! %16.t | ERROR! last mismatch", $time);
|
|
|
foreach(this.data[i])
|
foreach(this.data[i])
|
begin
|
begin
|
if(error_count > max_mismatches)
|
if(error_count > max_mismatches)
|
break;
|
break;
|
if(this.data[i] != to.data[i])
|
if(this.data[i] !== to.data[i])
|
begin
|
begin
|
$display("!!! %16.t | ERROR! | 0x%x | this != to | 0x%x != 0x%x", $time, i, this.data[i], to.data[i]);
|
$display("!!! %16.t | ERROR! | 0x%x | this != to | 0x%x != 0x%x", $time, i, this.data[i], to.data[i]);
|
error_count++;
|
error_count++;
|
end
|
end
|
end
|
end
|
endfunction: compare
|
endfunction: compare
|
|
|
|
|
// // --------------------------------------------------------------------
|
// // --------------------------------------------------------------------
|
// //
|
// //
|
// function void copy(ref riffa_transaction_class #(N) from);
|
// function void copy(ref riffa_transaction_class #(N) from);
|
// this.len = from.len;
|
// this.len = from.len;
|
// this.off = from.off;
|
// this.off = from.off;
|
// this.last = from.last;
|
// this.last = from.last;
|
// endfunction: copy
|
// endfunction: copy
|
|
|
|
|
// // --------------------------------------------------------------------
|
// // --------------------------------------------------------------------
|
// //
|
// //
|
// function riffa_transaction_class #(N) clone();
|
// function riffa_transaction_class #(N) clone();
|
// clone = new(0, 0, 0);
|
// clone = new(0, 0, 0);
|
// clone.copy(this);
|
// clone.copy(this);
|
// endfunction: clone
|
// endfunction: clone
|
|
|
|
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
function new(int len, int off, bit last);
|
function new(int len, int off, bit last);
|
this.data = new[get_data_size(len)];
|
this.data = new[get_data_size(len)];
|
this.len = len;
|
this.len = len;
|
this.off = off;
|
this.off = off;
|
this.last = last;
|
this.last = last;
|
endfunction: new
|
endfunction: new
|
|
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
//
|
//
|
endclass: riffa_transaction_class
|
endclass: riffa_transaction_class
|
|
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
// root port tx
|
// root port tx
|
class rp_tx_bfm_class #(N)
|
class rp_tx_bfm_class #(N)
|
extends blocking_transmission_q_class #(riffa_transaction_class #(N));
|
extends blocking_transmission_q_class #(riffa_transaction_class #(N));
|
|
|
virtual riffa_chnl_if #(.N(N)) chnl_bus;
|
virtual riffa_chnl_if #(.N(N)) chnl_bus;
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
//
|
//
|
task set_default;
|
task set_default;
|
|
|
chnl_bus.cb_rp_tx.rx <= 0;
|
chnl_bus.cb_rp_tx.rx <= 0;
|
chnl_bus.cb_rp_tx.rx_last <= 'bx;
|
chnl_bus.cb_rp_tx.rx_last <= 'bx;
|
chnl_bus.cb_rp_tx.rx_len <= 'bx;
|
chnl_bus.cb_rp_tx.rx_len <= 'bx;
|
chnl_bus.cb_rp_tx.rx_off <= 'bx;
|
chnl_bus.cb_rp_tx.rx_off <= 'bx;
|
chnl_bus.cb_rp_tx.rx_data <= 'bx;
|
chnl_bus.cb_rp_tx.rx_data <= 'bx;
|
chnl_bus.cb_rp_tx.rx_data_valid <= 0;
|
chnl_bus.cb_rp_tx.rx_data_valid <= 0;
|
|
|
endtask: set_default
|
endtask: set_default
|
|
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
//
|
//
|
event tx_done;
|
event tx_done;
|
|
|
task transmit(ref Q_T tr_h);
|
task transmit(ref Q_T tr_h);
|
|
|
@(chnl_bus.cb_rp_tx);
|
@(chnl_bus.cb_rp_tx);
|
chnl_bus.cb_rp_tx.rx_len <= tr_h.len; // must be => 4
|
chnl_bus.cb_rp_tx.rx_len <= tr_h.len; // must be => 4
|
chnl_bus.cb_rp_tx.rx_off <= tr_h.off;
|
chnl_bus.cb_rp_tx.rx_off <= tr_h.off;
|
chnl_bus.cb_rp_tx.rx_last <= tr_h.last;
|
chnl_bus.cb_rp_tx.rx_last <= tr_h.last;
|
chnl_bus.cb_rp_tx.rx <= 1;
|
chnl_bus.cb_rp_tx.rx <= 1;
|
|
|
@(chnl_bus.cb_rp_tx iff chnl_bus.cb_rp_tx.rx_ack);
|
@(chnl_bus.cb_rp_tx iff chnl_bus.cb_rp_tx.rx_ack);
|
chnl_bus.cb_rp_tx.rx_data_valid <= 1;
|
chnl_bus.cb_rp_tx.rx_data_valid <= 1;
|
|
|
foreach(tr_h.data[i])
|
foreach(tr_h.data[i])
|
begin
|
begin
|
chnl_bus.cb_rp_tx.rx_data <= tr_h.data[i];
|
chnl_bus.cb_rp_tx.rx_data <= tr_h.data[i];
|
@(chnl_bus.cb_rp_tx iff chnl_bus.cb_rp_tx.rx_data_ren);
|
@(chnl_bus.cb_rp_tx iff chnl_bus.cb_rp_tx.rx_data_ren);
|
end
|
end
|
|
|
set_default();
|
set_default();
|
->tx_done;
|
->tx_done;
|
endtask: transmit
|
endtask: transmit
|
|
|
|
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
//
|
//
|
function new(virtual riffa_chnl_if #(.N(N)) chnl_bus);
|
function new(virtual riffa_chnl_if #(.N(N)) chnl_bus);
|
this.chnl_bus = chnl_bus;
|
this.chnl_bus = chnl_bus;
|
fork
|
fork
|
set_default();
|
set_default();
|
join_none
|
join_none
|
endfunction: new
|
endfunction: new
|
|
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
//
|
//
|
endclass: rp_tx_bfm_class
|
endclass: rp_tx_bfm_class
|
|
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
// root port rx
|
// root port rx
|
class rp_rx_bfm_class #(N)
|
class rp_rx_bfm_class #(N)
|
extends blocking_transmission_q_class #(riffa_transaction_class #(N));
|
extends blocking_transmission_q_class #(riffa_transaction_class #(N));
|
|
|
virtual riffa_chnl_if #(.N(N)) chnl_bus;
|
virtual riffa_chnl_if #(.N(N)) chnl_bus;
|
mailbox #(riffa_transaction_class #(N)) rx_q;
|
mailbox #(riffa_transaction_class #(N)) rx_q;
|
|
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
//
|
//
|
task set_default;
|
task set_default;
|
|
|
chnl_bus.cb_rp_rx.tx_ack <= 0;
|
chnl_bus.cb_rp_rx.tx_ack <= 0;
|
chnl_bus.cb_rp_rx.tx_data_ren <= 0;
|
chnl_bus.cb_rp_rx.tx_data_ren <= 0;
|
|
|
endtask: set_default
|
endtask: set_default
|
|
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
//
|
//
|
event rx_done;
|
event rx_done;
|
|
|
task automatic transmit(ref Q_T tr_h);
|
task automatic transmit(ref Q_T tr_h);
|
int last;
|
int last;
|
int len;
|
int len;
|
int off;
|
int off;
|
|
|
@(chnl_bus.cb_rp_rx iff chnl_bus.cb_rp_rx.tx);
|
@(chnl_bus.cb_rp_rx iff chnl_bus.cb_rp_rx.tx);
|
|
|
last = chnl_bus.cb_rp_rx.tx_last;
|
last = chnl_bus.cb_rp_rx.tx_last;
|
len = chnl_bus.cb_rp_rx.tx_len; // must be => 4
|
len = chnl_bus.cb_rp_rx.tx_len; // must be => 4
|
off = chnl_bus.cb_rp_rx.tx_off;
|
off = chnl_bus.cb_rp_rx.tx_off;
|
tr_h = new(len, off, last);
|
tr_h = new(len, off, last);
|
|
|
chnl_bus.cb_rp_rx.tx_ack <= 1;
|
chnl_bus.cb_rp_rx.tx_ack <= 1;
|
chnl_bus.cb_rp_rx.tx_data_ren <= 1;
|
chnl_bus.cb_rp_rx.tx_data_ren <= 1;
|
|
|
fork
|
fork
|
@(chnl_bus.cb_rp_tx)
|
@(chnl_bus.cb_rp_tx)
|
chnl_bus.cb_rp_rx.tx_ack <= 0;
|
chnl_bus.cb_rp_rx.tx_ack <= 0;
|
join_none
|
join_none
|
|
|
// foreach(tr_h.data[i])
|
// foreach(tr_h.data[i])
|
// @(chnl_bus.cb_rp_tx)
|
// @(chnl_bus.cb_rp_tx)
|
// if(~chnl_bus.cb_rp_rx.tx)
|
// if(~chnl_bus.cb_rp_rx.tx)
|
// break;
|
// break;
|
// else if(chnl_bus.cb_rp_rx.tx_data_valid)
|
// else if(chnl_bus.cb_rp_rx.tx_data_valid)
|
// tr_h.data[i] <= chnl_bus.cb_rp_rx.tx_data;
|
// tr_h.data[i] <= chnl_bus.cb_rp_rx.tx_data;
|
|
|
foreach(tr_h.data[i])
|
foreach(tr_h.data[i])
|
@(chnl_bus.cb_rp_tx iff chnl_bus.cb_rp_rx.tx_data_valid)
|
@(chnl_bus.cb_rp_tx iff chnl_bus.cb_rp_rx.tx_data_valid)
|
tr_h.data[i] <= chnl_bus.cb_rp_rx.tx_data;
|
tr_h.data[i] <= chnl_bus.cb_rp_rx.tx_data;
|
|
|
rx_q.put(tr_h);
|
rx_q.put(tr_h);
|
set_default();
|
set_default();
|
->rx_done;
|
->rx_done;
|
endtask: transmit
|
endtask: transmit
|
|
|
|
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
//
|
//
|
function new(virtual riffa_chnl_if #(.N(N)) chnl_bus);
|
function new(virtual riffa_chnl_if #(.N(N)) chnl_bus);
|
this.chnl_bus = chnl_bus;
|
this.chnl_bus = chnl_bus;
|
this.rx_q = new();
|
this.rx_q = new();
|
fork
|
fork
|
set_default();
|
set_default();
|
join_none
|
join_none
|
endfunction: new
|
endfunction: new
|
|
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
//
|
//
|
endclass: rp_rx_bfm_class
|
endclass: rp_rx_bfm_class
|
|
|
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
//
|
//
|
endpackage: riffa_bfm_class_pkg
|
endpackage: riffa_bfm_class_pkg
|
|
|
|
|