//./rtl/dut.v
//////////////////////////////////////////////////
`timescale 1ns/1ps
`define PKT_RECV_IDLE 0
`define PKT_RECV_START 1
`define PKT_RECV_RECV 2
`define PKT_RECV_VALID 3
`define PKT_RECV_END 4
`define PKT_SENT_IDLE 0
`define PKT_SENT_VALID 1
`define PKT_SENT_END 2
`define PKT_SENT_FIN 3
module dut(
clk ,
rst_n ,
addr ,
din ,
rw ,
dout ,
txd ,
tx_vld ,
rxd ,
rx_vld
);
input clk ;
input rst_n ;
input [7:0 ] addr ;
input [31:0] din ;
input rw ;
output [31:0] dout ;
input [7:0 ] rxd ;
input rx_vld ;
output [7:0 ] txd ;
output tx_vld ;
wire clk ;
wire rst_n ;
wire [7:0 ] addr ;
wire [31:0] din ;
wire rw ;
reg [31:0] dout ;
wire [7:0 ] rxd ;
wire rx_vld ;
reg [7:0 ] txd ;
reg tx_vld ;
wire write ;
wire read ;
wire [31:0] config_reg ;
reg pkt_en;
reg [31:0] min_pkt_size ;
reg [31:0] max_pkt_size ;
reg [7:0 ] mem[0:512];
reg [9:0 ] mem_wr_ptr;
reg [9:0 ] mem_rd_ptr;
reg [9:0 ] need_to_sent_pkt_size;
reg [9:0 ] sending_pkt_size;
reg [15:0] header;
reg [2:0 ] pkt_recv_status;
reg [1:0 ] pkt_sent_status;
reg new_pkt;
reg one_pkt_sent;
reg [1:0 ] pkt_no;
assign write = (rw == 1'b0);
assign read = (rw == 1'b1);
assign config_reg = {31'h0, pkt_en};
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
pkt_en <= 1'b0;
end
else begin
if((addr == 8'h0) && (write == 1'b1)) begin
pkt_en <= din[0];
end
end
end
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
min_pkt_size <= 32'd64;
end
else begin
if((addr == 8'h4) && (write == 1'b1)) begin
if((din[9:0] >= 64) && (din[9:0] < max_pkt_size[9:0]))
min_pkt_size[9:0] <= din[9:0];
end
end
end
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
max_pkt_size <= 32'd512;
end
else begin
if((addr == 8'h8) && (write == 1'b1)) begin
if((din[9:0] <= 512) && (din[9:0] > min_pkt_size[9:0]))
max_pkt_size[9:0] <= din[9:0];
end
end
end
always @(*) begin
case(addr)
8'h0 : dout = config_reg;
8'h4 : dout = min_pkt_size;
8'h8 : dout = max_pkt_size;
default : dout = 32'h0;
endcase
end
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
pkt_recv_status <= 'h0;
pkt_recv_status <= `PKT_RECV_IDLE;
mem_wr_ptr <= 8'h0;
new_pkt <= 1'b0;
end
else begin
case(pkt_recv_status)
`PKT_RECV_IDLE: begin
mem_wr_ptr <= 8'h0;
if((rx_vld == 1'b1) && (pkt_en == 1'b1)) begin
mem_wr_ptr <= mem_wr_ptr + 1;
pkt_recv_status <= `PKT_RECV_START;
mem[mem_wr_ptr] <= rxd;
header[15:8] = rxd;
end
end
`PKT_RECV_START: begin
if(rx_vld == 1'b1) begin
mem_wr_ptr <= mem_wr_ptr + 1;
pkt_recv_status <= `PKT_RECV_RECV;
mem[mem_wr_ptr] <= rxd;
if(mem_wr_ptr == 1) begin
header[7:0] = rxd;
end
end
else begin
pkt_recv_status <= `PKT_RECV_END;
end
end
`PKT_RECV_RECV: begin
if(rx_vld == 1'b1) begin
if(mem_wr_ptr == max_pkt_size) begin
pkt_recv_status <= `PKT_RECV_END;
end
else begin
mem_wr_ptr <= mem_wr_ptr + 1;
pkt_recv_status <= `PKT_RECV_RECV;
mem[mem_wr_ptr] <= rxd;
end
end
else begin
pkt_recv_status <= `PKT_RECV_VALID;
end
end
`PKT_RECV_VALID: begin
if(mem_wr_ptr >= min_pkt_size && header == 16'h55d5) begin
new_pkt <= 1'b1;
need_to_sent_pkt_size <= mem_wr_ptr;
end
pkt_recv_status <= `PKT_RECV_END;
end
`PKT_RECV_END: begin
new_pkt <= 1'b0;
if(rx_vld == 1'b0) begin
pkt_recv_status <= `PKT_RECV_IDLE;
end
end
default : begin
end
endcase
end
end
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
pkt_sent_status <= `PKT_SENT_IDLE;
pkt_sent_status <= 'h0;
mem_rd_ptr <= 'h0;
sending_pkt_size <= 'h0;
txd <= 'h0;
tx_vld <= 1'b0;
one_pkt_sent <= 1'b0;
end
else begin
case(pkt_sent_status)
`PKT_SENT_IDLE: begin
if(pkt_no > 0) begin
pkt_sent_status <= `PKT_SENT_VALID;
sending_pkt_size <= need_to_sent_pkt_size;
mem_rd_ptr <= 'h0;
end
end
`PKT_SENT_VALID: begin
if(mem_rd_ptr < sending_pkt_size) begin
mem_rd_ptr <= mem_rd_ptr + 1;
txd <= mem[mem_rd_ptr];
tx_vld <= 1'b1;
end
else begin
pkt_sent_status <= `PKT_SENT_END;
txd <= 'h0;
tx_vld <= 1'b0;
end
end
`PKT_SENT_END: begin
pkt_sent_status <= `PKT_SENT_FIN;
one_pkt_sent <= 1'b1;
end
`PKT_SENT_FIN: begin
pkt_sent_status <= `PKT_SENT_IDLE;
one_pkt_sent <= 1'b0;
end
default: begin
end
endcase
end
end
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
pkt_no <= 'h0;
end
else begin
if(new_pkt == 1'b1) begin
pkt_no <= pkt_no + 1;
end
else if(one_pkt_sent == 1'b1) begin
pkt_no <= pkt_no - 1;
end
end
end
endmodule
`define PKT_RECV_IDLE 0
`define PKT_RECV_START 1
`define PKT_RECV_RECV 2
`define PKT_RECV_VALID 3
`define PKT_RECV_END 4
`define PKT_SENT_IDLE 0
`define PKT_SENT_VALID 1
`define PKT_SENT_END 2
`define PKT_SENT_FIN 3
module dut(
clk ,
rst_n ,
addr ,
din ,
rw ,
dout ,
txd ,
tx_vld ,
rxd ,
rx_vld
);
input clk ;
input rst_n ;
input [7:0 ] addr ;
input [31:0] din ;
input rw ;
output [31:0] dout ;
input [7:0 ] rxd ;
input rx_vld ;
output [7:0 ] txd ;
output tx_vld ;
wire clk ;
wire rst_n ;
wire [7:0 ] addr ;
wire [31:0] din ;
wire rw ;
reg [31:0] dout ;
wire [7:0 ] rxd ;
wire rx_vld ;
reg [7:0 ] txd ;
reg tx_vld ;
wire write ;
wire read ;
wire [31:0] config_reg ;
reg pkt_en;
reg [31:0] min_pkt_size ;
reg [31:0] max_pkt_size ;
reg [7:0 ] mem[0:512];
reg [9:0 ] mem_wr_ptr;
reg [9:0 ] mem_rd_ptr;
reg [9:0 ] need_to_sent_pkt_size;
reg [9:0 ] sending_pkt_size;
reg [15:0] header;
reg [2:0 ] pkt_recv_status;
reg [1:0 ] pkt_sent_status;
reg new_pkt;
reg one_pkt_sent;
reg [1:0 ] pkt_no;
assign write = (rw == 1'b0);
assign read = (rw == 1'b1);
assign config_reg = {31'h0, pkt_en};
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
pkt_en <= 1'b0;
end
else begin
if((addr == 8'h0) && (write == 1'b1)) begin
pkt_en <= din[0];
end
end
end
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
min_pkt_size <= 32'd64;
end
else begin
if((addr == 8'h4) && (write == 1'b1)) begin
if((din[9:0] >= 64) && (din[9:0] < max_pkt_size[9:0]))
min_pkt_size[9:0] <= din[9:0];
end
end
end
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
max_pkt_size <= 32'd512;
end
else begin
if((addr == 8'h8) && (write == 1'b1)) begin
if((din[9:0] <= 512) && (din[9:0] > min_pkt_size[9:0]))
max_pkt_size[9:0] <= din[9:0];
end
end
end
always @(*) begin
case(addr)
8'h0 : dout = config_reg;
8'h4 : dout = min_pkt_size;
8'h8 : dout = max_pkt_size;
default : dout = 32'h0;
endcase
end
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
pkt_recv_status <= 'h0;
pkt_recv_status <= `PKT_RECV_IDLE;
mem_wr_ptr <= 8'h0;
new_pkt <= 1'b0;
end
else begin
case(pkt_recv_status)
`PKT_RECV_IDLE: begin
mem_wr_ptr <= 8'h0;
if((rx_vld == 1'b1) && (pkt_en == 1'b1)) begin
mem_wr_ptr <= mem_wr_ptr + 1;
pkt_recv_status <= `PKT_RECV_START;
mem[mem_wr_ptr] <= rxd;
header[15:8] = rxd;
end
end
`PKT_RECV_START: begin
if(rx_vld == 1'b1) begin
mem_wr_ptr <= mem_wr_ptr + 1;
pkt_recv_status <= `PKT_RECV_RECV;
mem[mem_wr_ptr] <= rxd;
if(mem_wr_ptr == 1) begin
header[7:0] = rxd;
end
end
else begin
pkt_recv_status <= `PKT_RECV_END;
end
end
`PKT_RECV_RECV: begin
if(rx_vld == 1'b1) begin
if(mem_wr_ptr == max_pkt_size) begin
pkt_recv_status <= `PKT_RECV_END;
end
else begin
mem_wr_ptr <= mem_wr_ptr + 1;
pkt_recv_status <= `PKT_RECV_RECV;
mem[mem_wr_ptr] <= rxd;
end
end
else begin
pkt_recv_status <= `PKT_RECV_VALID;
end
end
`PKT_RECV_VALID: begin
if(mem_wr_ptr >= min_pkt_size && header == 16'h55d5) begin
new_pkt <= 1'b1;
need_to_sent_pkt_size <= mem_wr_ptr;
end
pkt_recv_status <= `PKT_RECV_END;
end
`PKT_RECV_END: begin
new_pkt <= 1'b0;
if(rx_vld == 1'b0) begin
pkt_recv_status <= `PKT_RECV_IDLE;
end
end
default : begin
end
endcase
end
end
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
pkt_sent_status <= `PKT_SENT_IDLE;
pkt_sent_status <= 'h0;
mem_rd_ptr <= 'h0;
sending_pkt_size <= 'h0;
txd <= 'h0;
tx_vld <= 1'b0;
one_pkt_sent <= 1'b0;
end
else begin
case(pkt_sent_status)
`PKT_SENT_IDLE: begin
if(pkt_no > 0) begin
pkt_sent_status <= `PKT_SENT_VALID;
sending_pkt_size <= need_to_sent_pkt_size;
mem_rd_ptr <= 'h0;
end
end
`PKT_SENT_VALID: begin
if(mem_rd_ptr < sending_pkt_size) begin
mem_rd_ptr <= mem_rd_ptr + 1;
txd <= mem[mem_rd_ptr];
tx_vld <= 1'b1;
end
else begin
pkt_sent_status <= `PKT_SENT_END;
txd <= 'h0;
tx_vld <= 1'b0;
end
end
`PKT_SENT_END: begin
pkt_sent_status <= `PKT_SENT_FIN;
one_pkt_sent <= 1'b1;
end
`PKT_SENT_FIN: begin
pkt_sent_status <= `PKT_SENT_IDLE;
one_pkt_sent <= 1'b0;
end
default: begin
end
endcase
end
end
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
pkt_no <= 'h0;
end
else begin
if(new_pkt == 1'b1) begin
pkt_no <= pkt_no + 1;
end
else if(one_pkt_sent == 1'b1) begin
pkt_no <= pkt_no - 1;
end
end
end
endmodule
//////////////////////////////////////////////////
//./env/cpu_interface_env/cpu_interface.svi
//////////////////////////////////////////////////
`ifndef __CPU_INTERFACE_SVI__
`define __CPU_INTERFACE_SVI__
interface cpu_interface (input logic clk);
logic rst_n ;
logic [7:0 ] addr ;
logic [31:0] din ;
logic rw ;
logic [31:0] dout ;
clocking cb @(posedge clk);
default input #1 output #1;
output addr ;
output rw ;
output dout ;
input din ;
endclocking
modport master(clocking cb, output rst_n);
endinterface
`endif
`define __CPU_INTERFACE_SVI__
interface cpu_interface (input logic clk);
logic rst_n ;
logic [7:0 ] addr ;
logic [31:0] din ;
logic rw ;
logic [31:0] dout ;
clocking cb @(posedge clk);
default input #1 output #1;
output addr ;
output rw ;
output dout ;
input din ;
endclocking
modport master(clocking cb, output rst_n);
endinterface
`endif
//////////////////////////////////////////////////
//./env/cpu_interface_env/cpu_trans.sv
//////////////////////////////////////////////////
`ifndef __CPU_TRANS_SV__
`define __CPU_TRANS_SV__
class cpu_trans extends vmm_data;
static vmm_log log = new("cpu_trans", "class");
rand logic [7:0] addr;
rand logic rw;
rand logic [31:0] dout;
logic [31:0] din = 32'h0;
extern function new();
extern virtual function vmm_data copy(vmm_data to);
extern virtual function string psdisplay(string prefix );
endclass
function cpu_trans::new();
super.new(this.log);
endfunction
function vmm_data cpu_trans::copy(vmm_data to = null);
cpu_trans cpy;
if(to == null)
cpy = new();
else if(!$cast(cpy, to)) begin
`vmm_fatal(this.log, "Cannot cast to to cpy in cpu_trans");
copy = null;
return copy;
end
super.copy_data(cpy);
cpy.addr = this.addr;
cpy.rw = this.rw;
cpy.dout = this.dout;
cpy.din = this.din;
copy = cpy;
endfunction
function string cpu_trans::psdisplay(string prefix = "Note");
$write(psdisplay, "[%s]%t addr = %0h, dout = %0h, rw = %d, din = %0h", prefix, $realtime, addr, dout, rw, din);
endfunction
`vmm_channel(cpu_trans)
`vmm_atomic_gen(cpu_trans, "CPU Transaction Atomic")
`vmm_scenario_gen(cpu_trans, "CPU Transaction Scenario")
`endif
`define __CPU_TRANS_SV__
class cpu_trans extends vmm_data;
static vmm_log log = new("cpu_trans", "class");
rand logic [7:0] addr;
rand logic rw;
rand logic [31:0] dout;
logic [31:0] din = 32'h0;
extern function new();
extern virtual function vmm_data copy(vmm_data to);
extern virtual function string psdisplay(string prefix );
endclass
function cpu_trans::new();
super.new(this.log);
endfunction
function vmm_data cpu_trans::copy(vmm_data to = null);
cpu_trans cpy;
if(to == null)
cpy = new();
else if(!$cast(cpy, to)) begin
`vmm_fatal(this.log, "Cannot cast to to cpy in cpu_trans");
copy = null;
return copy;
end
super.copy_data(cpy);
cpy.addr = this.addr;
cpy.rw = this.rw;
cpy.dout = this.dout;
cpy.din = this.din;
copy = cpy;
endfunction
function string cpu_trans::psdisplay(string prefix = "Note");
$write(psdisplay, "[%s]%t addr = %0h, dout = %0h, rw = %d, din = %0h", prefix, $realtime, addr, dout, rw, din);
endfunction
`vmm_channel(cpu_trans)
`vmm_atomic_gen(cpu_trans, "CPU Transaction Atomic")
`vmm_scenario_gen(cpu_trans, "CPU Transaction Scenario")
`endif
//////////////////////////////////////////////////
//./env/cpu_interface_env/cpu_driver.sv
//////////////////////////////////////////////////
`ifndef __CPU_DRIVER_SV__
`define __CPU_DRIVER_SV__
`include "vmm.sv"
`include "cpu_interface.svi"
`include "cpu_trans.sv"
`include "cpu_sb.sv"
class cpu_driver extends vmm_xactor;
string name;
virtual cpu_interface.master cpu_intf;
cpu_trans_channel gen2drv_chan ;
extern function new (
string instance,
integer stream_id = -1,
virtual cpu_interface.master cpu_intf,
cpu_trans_channel gen2drv_chan = null
);
extern virtual task main() ;
extern virtual task reset() ;
endclass
//callback class
virtual class cpu_driver_callbacks extends vmm_xactor_callbacks;
virtual task driver_pre_tx (
cpu_driver xactor,
ref cpu_trans trans,
ref bit drop
);
endtask
virtual task driver_post_tx (
cpu_driver xactor,
cpu_trans trans
);
endtask
endclass
class cpu_driver_to_sb extends cpu_driver_callbacks;
cpu_sb cpu_scb;
function new(cpu_sb cpu_scb);
this.cpu_scb = cpu_scb;
endfunction: new
virtual task driver_post_tx (cpu_driver xactor, cpu_trans trans);
cpu_scb.compare(trans);
endtask
endclass
function cpu_driver::new(
string instance,
integer stream_id,
virtual cpu_interface.master cpu_intf,
cpu_trans_channel gen2drv_chan
);
super.new("CPU Driver", instance, stream_id) ;
this.cpu_intf = cpu_intf;
if(gen2drv_chan == null)
gen2drv_chan = new("CPU generator to driver channel", instance);
this.gen2drv_chan = gen2drv_chan;
endfunction
task cpu_driver::main() ;
cpu_trans tr;
cpu_trans cpy_tr;
bit drop;
fork
super.main();
join_none
while (1) begin
this.wait_if_stopped_or_empty(this.gen2drv_chan) ;
gen2drv_chan.get(tr);
`vmm_callback(cpu_driver_callbacks, driver_pre_tx(this, tr, drop));
if (drop == 1) begin
`vmm_note(log, tr.psdisplay("Dropped"));
continue;
end
@(cpu_intf.cb);
cpu_intf.cb.addr <= tr.addr;
cpu_intf.cb.dout <= tr.dout;
cpu_intf.cb.rw <= tr.rw;
if(tr.rw == 1'b1) begin
@(cpu_intf.cb);
tr.din = cpu_intf.cb.din;
end
$cast(cpy_tr, tr.copy());
`vmm_callback(cpu_driver_callbacks, driver_post_tx(this, cpy_tr));
`vmm_debug(log, tr.psdisplay("CPU Driver ==>"));
end
endtask
task cpu_driver::reset() ;
@(cpu_intf.cb);
cpu_intf.rst_n = 1'b0;
@(cpu_intf.cb);
cpu_intf.rst_n = 1'b1;
@(cpu_intf.cb);
endtask
`endif
`define __CPU_DRIVER_SV__
`include "vmm.sv"
`include "cpu_interface.svi"
`include "cpu_trans.sv"
`include "cpu_sb.sv"
class cpu_driver extends vmm_xactor;
string name;
virtual cpu_interface.master cpu_intf;
cpu_trans_channel gen2drv_chan ;
extern function new (
string instance,
integer stream_id = -1,
virtual cpu_interface.master cpu_intf,
cpu_trans_channel gen2drv_chan = null
);
extern virtual task main() ;
extern virtual task reset() ;
endclass
//callback class
virtual class cpu_driver_callbacks extends vmm_xactor_callbacks;
virtual task driver_pre_tx (
cpu_driver xactor,
ref cpu_trans trans,
ref bit drop
);
endtask
virtual task driver_post_tx (
cpu_driver xactor,
cpu_trans trans
);
endtask
endclass
class cpu_driver_to_sb extends cpu_driver_callbacks;
cpu_sb cpu_scb;
function new(cpu_sb cpu_scb);
this.cpu_scb = cpu_scb;
endfunction: new
virtual task driver_post_tx (cpu_driver xactor, cpu_trans trans);
cpu_scb.compare(trans);
endtask
endclass
function cpu_driver::new(
string instance,
integer stream_id,
virtual cpu_interface.master cpu_intf,
cpu_trans_channel gen2drv_chan
);
super.new("CPU Driver", instance, stream_id) ;
this.cpu_intf = cpu_intf;
if(gen2drv_chan == null)
gen2drv_chan = new("CPU generator to driver channel", instance);
this.gen2drv_chan = gen2drv_chan;
endfunction
task cpu_driver::main() ;
cpu_trans tr;
cpu_trans cpy_tr;
bit drop;
fork
super.main();
join_none
while (1) begin
this.wait_if_stopped_or_empty(this.gen2drv_chan) ;
gen2drv_chan.get(tr);
`vmm_callback(cpu_driver_callbacks, driver_pre_tx(this, tr, drop));
if (drop == 1) begin
`vmm_note(log, tr.psdisplay("Dropped"));
continue;
end
@(cpu_intf.cb);
cpu_intf.cb.addr <= tr.addr;
cpu_intf.cb.dout <= tr.dout;
cpu_intf.cb.rw <= tr.rw;
if(tr.rw == 1'b1) begin
@(cpu_intf.cb);
tr.din = cpu_intf.cb.din;
end
$cast(cpy_tr, tr.copy());
`vmm_callback(cpu_driver_callbacks, driver_post_tx(this, cpy_tr));
`vmm_debug(log, tr.psdisplay("CPU Driver ==>"));
end
endtask
task cpu_driver::reset() ;
@(cpu_intf.cb);
cpu_intf.rst_n = 1'b0;
@(cpu_intf.cb);
cpu_intf.rst_n = 1'b1;
@(cpu_intf.cb);
endtask
`endif
//////////////////////////////////////////////////
//./env/cpu_interface_env/cpu_sb.sv
//////////////////////////////////////////////////
`ifndef __CPU_SB_SV__
`define __CPU_SB_SV__
`include "vmm.sv"
`include "cpu_trans.sv"
`include "cpu_driver.sv"
class cpu_sb;
string name;
logic [31:0] cpu_reg [7:0];
integer error_no = 0;
integer total_no = 0;
extern function new(string name = "CPU Scoreboard");
extern virtual function bit compare(vmm_data data);
extern virtual function report(string prefix);
endclass
//class cpu_driver_to_sb extends cpu_driver_callbacks;
// cpu_sb cpu_scb;
//
// function new(cpu_sb cpu_scb);
// this.cpu_scb = cpu_scb;
// endfunction: new
//
// virtual task driver_post_tx (cpu_driver xactor, cpu_trans trans);
// cpu_scb.compare(trans);
// endtask
//
//endclass
function cpu_sb::new(string name);
this.name = name;
for(int i=0; i<128; i++) begin
cpu_reg[i] = 32'h0;
end
endfunction
function bit cpu_sb::compare(vmm_data data);
cpu_trans tr;
string message;
$cast(tr, data);
if(tr.rw == 1'b0) begin
cpu_reg[tr.addr] = tr.din;
end
else if(tr.rw == 1'b1) begin
if(cpu_reg[tr.addr] != tr.din) begin
message = $psprintf("[Error] %t Comparision result is not correct\n", $realtime);
message = { message, $psprintf("cpu_reg[%d] = %0h, tr.din = %0h\n", tr.addr, cpu_reg[tr.addr], tr.din) };
$display(message);
error_no++;
end
else begin
$display("[Note] %t comparison correct", $realtime);
end
end
else begin
$display("[Error] tr.rw can only be 0 or 1");
error_no++;
end
endfunction
function cpu_sb::report(string prefix);
$display("Total: %d, Error: %d", total_no, error_no);
endfunction
`endif
`define __CPU_SB_SV__
`include "vmm.sv"
`include "cpu_trans.sv"
`include "cpu_driver.sv"
class cpu_sb;
string name;
logic [31:0] cpu_reg [7:0];
integer error_no = 0;
integer total_no = 0;
extern function new(string name = "CPU Scoreboard");
extern virtual function bit compare(vmm_data data);
extern virtual function report(string prefix);
endclass
//class cpu_driver_to_sb extends cpu_driver_callbacks;
// cpu_sb cpu_scb;
//
// function new(cpu_sb cpu_scb);
// this.cpu_scb = cpu_scb;
// endfunction: new
//
// virtual task driver_post_tx (cpu_driver xactor, cpu_trans trans);
// cpu_scb.compare(trans);
// endtask
//
//endclass
function cpu_sb::new(string name);
this.name = name;
for(int i=0; i<128; i++) begin
cpu_reg[i] = 32'h0;
end
endfunction
function bit cpu_sb::compare(vmm_data data);
cpu_trans tr;
string message;
$cast(tr, data);
if(tr.rw == 1'b0) begin
cpu_reg[tr.addr] = tr.din;
end
else if(tr.rw == 1'b1) begin
if(cpu_reg[tr.addr] != tr.din) begin
message = $psprintf("[Error] %t Comparision result is not correct\n", $realtime);
message = { message, $psprintf("cpu_reg[%d] = %0h, tr.din = %0h\n", tr.addr, cpu_reg[tr.addr], tr.din) };
$display(message);
error_no++;
end
else begin
$display("[Note] %t comparison correct", $realtime);
end
end
else begin
$display("[Error] tr.rw can only be 0 or 1");
error_no++;
end
endfunction
function cpu_sb::report(string prefix);
$display("Total: %d, Error: %d", total_no, error_no);
endfunction
`endif
//////////////////////////////////////////////////
//./env/cpu_interface_env/cpu_env.sv
//////////////////////////////////////////////////
`ifndef __CPU_ENV_SV__
`define __CPU_ENV_SV__
`include "cpu_interface.svi"
`include "cpu_trans.sv"
`include "cpu_driver.sv"
`include "cpu_sb.sv"
class cpu_env extends vmm_env;
virtual cpu_interface.master cpu_intf;
vmm_log log;
cpu_trans_channel gen2drv_chan;
cpu_trans_atomic_gen cpu_gen;
cpu_driver cpu_drv;
cpu_sb cpu_scb;
cpu_driver_to_sb cpu_drv_cbs_scb;
extern function new(virtual cpu_interface.master cpu_intf);
extern virtual function void gen_cfg();
extern virtual function void build();
extern virtual task reset_dut();
extern virtual task cfg_dut();
extern virtual task start();
extern virtual task wait_for_end();
extern virtual task stop();
extern virtual task cleanup();
extern virtual task report();
endclass
function cpu_env::new(virtual cpu_interface.master cpu_intf);
super.new("CPU ENV");
this.cpu_intf = cpu_intf;
log = new("cpu", "env");
endfunction
function void cpu_env::gen_cfg();
super.gen_cfg();
endfunction
function void cpu_env::build();
super.build();
gen2drv_chan = new("CPU Generator to Driver Channel", "channel");
cpu_gen = new("CPU Generator", 1, gen2drv_chan);
cpu_drv = new("CPU Driver", 1, cpu_intf, gen2drv_chan);
cpu_scb = new("CPU Scoreboard");
cpu_drv_cbs_scb = new(cpu_scb);
cpu_drv.append_callback(cpu_drv_cbs_scb);
endfunction
task cpu_env::reset_dut();
super.reset_dut();
cpu_drv.reset();
endtask
task cpu_env::cfg_dut();
super.cfg_dut();
endtask
task cpu_env::start();
super.start();
cpu_gen.start_xactor();
cpu_drv.start_xactor();
endtask
task cpu_env::wait_for_end();
super.wait_for_end();
fork
cpu_gen.notify.wait_for(cpu_trans_atomic_gen::DONE);
join_any
endtask
task cpu_env::stop();
super.stop();
cpu_gen.stop_xactor();
cpu_drv.stop_xactor();
endtask
task cpu_env::cleanup();
super.cleanup();
endtask
task cpu_env::report();
super.report();
endtask
`endif
`define __CPU_ENV_SV__
`include "cpu_interface.svi"
`include "cpu_trans.sv"
`include "cpu_driver.sv"
`include "cpu_sb.sv"
class cpu_env extends vmm_env;
virtual cpu_interface.master cpu_intf;
vmm_log log;
cpu_trans_channel gen2drv_chan;
cpu_trans_atomic_gen cpu_gen;
cpu_driver cpu_drv;
cpu_sb cpu_scb;
cpu_driver_to_sb cpu_drv_cbs_scb;
extern function new(virtual cpu_interface.master cpu_intf);
extern virtual function void gen_cfg();
extern virtual function void build();
extern virtual task reset_dut();
extern virtual task cfg_dut();
extern virtual task start();
extern virtual task wait_for_end();
extern virtual task stop();
extern virtual task cleanup();
extern virtual task report();
endclass
function cpu_env::new(virtual cpu_interface.master cpu_intf);
super.new("CPU ENV");
this.cpu_intf = cpu_intf;
log = new("cpu", "env");
endfunction
function void cpu_env::gen_cfg();
super.gen_cfg();
endfunction
function void cpu_env::build();
super.build();
gen2drv_chan = new("CPU Generator to Driver Channel", "channel");
cpu_gen = new("CPU Generator", 1, gen2drv_chan);
cpu_drv = new("CPU Driver", 1, cpu_intf, gen2drv_chan);
cpu_scb = new("CPU Scoreboard");
cpu_drv_cbs_scb = new(cpu_scb);
cpu_drv.append_callback(cpu_drv_cbs_scb);
endfunction
task cpu_env::reset_dut();
super.reset_dut();
cpu_drv.reset();
endtask
task cpu_env::cfg_dut();
super.cfg_dut();
endtask
task cpu_env::start();
super.start();
cpu_gen.start_xactor();
cpu_drv.start_xactor();
endtask
task cpu_env::wait_for_end();
super.wait_for_end();
fork
cpu_gen.notify.wait_for(cpu_trans_atomic_gen::DONE);
join_any
endtask
task cpu_env::stop();
super.stop();
cpu_gen.stop_xactor();
cpu_drv.stop_xactor();
endtask
task cpu_env::cleanup();
super.cleanup();
endtask
task cpu_env::report();
super.report();
endtask
`endif
//////////////////////////////////////////////////
//./env/packet_env/pkt_interface.svi
//////////////////////////////////////////////////
`ifndef __PKT_INTERFACE_SVI__
`define __PKT_INTERFACE_SVI__
interface pkt_interface (input logic clk);
logic rst_n ;
logic [7:0] rxd ;
logic rx_vld ;
logic [7:0] txd ;
logic tx_vld ;
clocking cb @(posedge clk);
default input #1 output #1;
output rst_n ;
output txd ;
output tx_vld ;
input rxd ;
input rx_vld ;
endclocking
modport master(clocking cb, output rst_n);
endinterface
`endif
`define __PKT_INTERFACE_SVI__
interface pkt_interface (input logic clk);
logic rst_n ;
logic [7:0] rxd ;
logic rx_vld ;
logic [7:0] txd ;
logic tx_vld ;
clocking cb @(posedge clk);
default input #1 output #1;
output rst_n ;
output txd ;
output tx_vld ;
input rxd ;
input rx_vld ;
endclocking
modport master(clocking cb, output rst_n);
endinterface
`endif
//////////////////////////////////////////////////
//./env/packet_env/pkt_trans.sv
//////////////////////////////////////////////////
`ifndef __PKT_TRANS_SV__
`define __PKT_TRANS_SV__
`include "vmm.sv"
class pkt_trans extends vmm_data;
static vmm_log log = new("pkt_trans", "class");
typedef enum {GOOD, BAD} head_type;
typedef enum {LONG, SHORT, NORMAL} packet_length;
rand head_type pkt_head_type ;
rand packet_length pkt_packet_length ;
rand logic [15:0] header ;
rand logic [7:0 ] payload[$] ;
extern function new();
extern virtual function vmm_data copy(vmm_data to);
extern virtual function string psdisplay(string prefix );
extern function bit compare(vmm_data to, output string diff, input int kind = -1);
extern function int unsigned byte_pack(ref logic [7:0] bytes[], input int unsigned offset, input int kind = -1);
constraint con_head_type {
solve pkt_head_type before header;
pkt_head_type dist {GOOD := 5, BAD := 1};
(pkt_head_type == GOOD) -> (header == 16'h55d5);
(pkt_head_type == BAD) -> (header inside {[0:16'h55d4], [16'h55d6:16'hffff]});
}
constraint con_pkt_len {
solve pkt_packet_length before payload;
pkt_packet_length dist {LONG := 1, SHORT := 1, NORMAL := 5};
(pkt_packet_length == LONG) -> (payload.size() inside {[0:49]});
(pkt_packet_length == SHORT) -> (payload.size() inside {[50:500]});
(pkt_packet_length == NORMAL) -> (payload.size() inside {[501:600]});
}
endclass
function pkt_trans::new();
super.new(this.log);
endfunction
function bit pkt_trans::compare(vmm_data to, output string diff, input int kind = -1);
pkt_trans tr;
$cast(tr, to);
if(header != tr.header) begin
diff = "Header Mismatch:\n";
diff = { diff, $psprintf("Header Sent: %p\nHeader Received: %p", header, tr.header) };
return 0;
end
if (payload.size() != tr.payload.size()) begin
diff = "Payload Size Mismatch:\n";
diff = { diff, $psprintf("payload.size() = %0d, tr.payload.size() = %0d\n", payload.size(), tr.payload.size()) };
return 0;
end
if (payload == tr.payload) ;
else begin
diff = "Payload Content Mismatch:\n";
diff = { diff, $psprintf("Packet Sent: %p\nPkt Received: %p", payload, tr.payload) };
return 0;
end
diff = "Successfully Compared";
return 1;
endfunction
function string pkt_trans::psdisplay(string prefix);
$write(psdisplay, "[%s]%t", prefix, $realtime);
$write(psdisplay, " [%s]%t header = %0h, payload size = %0d", prefix, $realtime, header, payload.size());
foreach(payload[i])
$display(psdisplay, " [%s]%t payload[%0d] = %0d", prefix, $realtime, i, payload[i]);
endfunction
function int unsigned pkt_trans::byte_pack(ref logic [7:0] bytes[], input int unsigned offset, input int kind = -1);
if(bytes.size() >= 2) begin
header[15:8] = bytes[0];
header[7:0] = bytes[1];
end
for(int i=2; i<bytes.size(); i++) begin
payload.push_back(bytes[i]);
end
return 1;
endfunction
function vmm_data pkt_trans::copy(vmm_data to = null);
pkt_trans cpy;
if(to == null)
cpy = new();
else if(!$cast(cpy, to)) begin
`vmm_fatal(this.log, "Cannot cast to to cpy in pkt_trans");
copy = null;
return copy;
end
super.copy_data(cpy);
cpy.pkt_head_type = this.pkt_head_type ;
cpy.pkt_packet_length = this.pkt_packet_length ;
cpy.header = this.header;
foreach(this.payload[i]) begin
cpy.payload.push_back(this.payload[i]);
end
copy = cpy;
endfunction
`vmm_channel(pkt_trans)
`vmm_atomic_gen(pkt_trans, "Packet Transaction Atomic")
`vmm_scenario_gen(pkt_trans, "Packet Transaction Scenario")
`endif
`define __PKT_TRANS_SV__
`include "vmm.sv"
class pkt_trans extends vmm_data;
static vmm_log log = new("pkt_trans", "class");
typedef enum {GOOD, BAD} head_type;
typedef enum {LONG, SHORT, NORMAL} packet_length;
rand head_type pkt_head_type ;
rand packet_length pkt_packet_length ;
rand logic [15:0] header ;
rand logic [7:0 ] payload[$] ;
extern function new();
extern virtual function vmm_data copy(vmm_data to);
extern virtual function string psdisplay(string prefix );
extern function bit compare(vmm_data to, output string diff, input int kind = -1);
extern function int unsigned byte_pack(ref logic [7:0] bytes[], input int unsigned offset, input int kind = -1);
constraint con_head_type {
solve pkt_head_type before header;
pkt_head_type dist {GOOD := 5, BAD := 1};
(pkt_head_type == GOOD) -> (header == 16'h55d5);
(pkt_head_type == BAD) -> (header inside {[0:16'h55d4], [16'h55d6:16'hffff]});
}
constraint con_pkt_len {
solve pkt_packet_length before payload;
pkt_packet_length dist {LONG := 1, SHORT := 1, NORMAL := 5};
(pkt_packet_length == LONG) -> (payload.size() inside {[0:49]});
(pkt_packet_length == SHORT) -> (payload.size() inside {[50:500]});
(pkt_packet_length == NORMAL) -> (payload.size() inside {[501:600]});
}
endclass
function pkt_trans::new();
super.new(this.log);
endfunction
function bit pkt_trans::compare(vmm_data to, output string diff, input int kind = -1);
pkt_trans tr;
$cast(tr, to);
if(header != tr.header) begin
diff = "Header Mismatch:\n";
diff = { diff, $psprintf("Header Sent: %p\nHeader Received: %p", header, tr.header) };
return 0;
end
if (payload.size() != tr.payload.size()) begin
diff = "Payload Size Mismatch:\n";
diff = { diff, $psprintf("payload.size() = %0d, tr.payload.size() = %0d\n", payload.size(), tr.payload.size()) };
return 0;
end
if (payload == tr.payload) ;
else begin
diff = "Payload Content Mismatch:\n";
diff = { diff, $psprintf("Packet Sent: %p\nPkt Received: %p", payload, tr.payload) };
return 0;
end
diff = "Successfully Compared";
return 1;
endfunction
function string pkt_trans::psdisplay(string prefix);
$write(psdisplay, "[%s]%t", prefix, $realtime);
$write(psdisplay, " [%s]%t header = %0h, payload size = %0d", prefix, $realtime, header, payload.size());
foreach(payload[i])
$display(psdisplay, " [%s]%t payload[%0d] = %0d", prefix, $realtime, i, payload[i]);
endfunction
function int unsigned pkt_trans::byte_pack(ref logic [7:0] bytes[], input int unsigned offset, input int kind = -1);
if(bytes.size() >= 2) begin
header[15:8] = bytes[0];
header[7:0] = bytes[1];
end
for(int i=2; i<bytes.size(); i++) begin
payload.push_back(bytes[i]);
end
return 1;
endfunction
function vmm_data pkt_trans::copy(vmm_data to = null);
pkt_trans cpy;
if(to == null)
cpy = new();
else if(!$cast(cpy, to)) begin
`vmm_fatal(this.log, "Cannot cast to to cpy in pkt_trans");
copy = null;
return copy;
end
super.copy_data(cpy);
cpy.pkt_head_type = this.pkt_head_type ;
cpy.pkt_packet_length = this.pkt_packet_length ;
cpy.header = this.header;
foreach(this.payload[i]) begin
cpy.payload.push_back(this.payload[i]);
end
copy = cpy;
endfunction
`vmm_channel(pkt_trans)
`vmm_atomic_gen(pkt_trans, "Packet Transaction Atomic")
`vmm_scenario_gen(pkt_trans, "Packet Transaction Scenario")
`endif
//////////////////////////////////////////////////
//./env/packet_env/pkt_driver.sv
//////////////////////////////////////////////////
`ifndef __PKT_DRIVER_SV__
`define __PKT_DRIVER_SV__
`include "vmm.sv"
`include "pkt_interface.svi"
`include "pkt_trans.sv"
class pkt_driver extends vmm_xactor;
string name;
virtual pkt_interface.master pkt_intf;
pkt_trans_channel gen2drv_chan;
extern function new(
string instance,
integer stream_id = -1,
virtual pkt_interface.master pkt_intf,
pkt_trans_channel gen2drv_chan = null
);
extern virtual task main() ;
extern virtual task reset() ;
endclass
//callback class
virtual class pkt_driver_callbacks extends vmm_xactor_callbacks;
virtual task driver_pre_tx (
pkt_driver xactor,
ref pkt_trans trans,
ref bit drop
);
endtask
virtual task driver_post_tx (
pkt_driver xactor,
pkt_trans trans
);
endtask
endclass
function pkt_driver::new(
string instance,
integer stream_id = -1,
virtual pkt_interface.master pkt_intf,
pkt_trans_channel gen2drv_chan = null
);
super.new("Packet Driver", instance, stream_id) ;
this.pkt_intf = pkt_intf;
if(gen2drv_chan == null)
gen2drv_chan = new("Packet generator to driver channel", instance);
this.gen2drv_chan = gen2drv_chan;
endfunction
task pkt_driver::main();
integer delay = 0;
pkt_trans tr;
pkt_trans tr_cpy;
bit drop;
fork
super.main();
join_none
while (1) begin
this.wait_if_stopped_or_empty(this.gen2drv_chan) ;
gen2drv_chan.get(tr);
$cast(tr_cpy, tr.copy());
`vmm_callback(pkt_driver_callbacks, driver_pre_tx(this, tr_cpy, drop));
if (drop == 1) begin
`vmm_note(log, tr.psdisplay("Dropped"));
continue;
end
@(pkt_intf.cb);
pkt_intf.cb.tx_vld <= 1'b1;
pkt_intf.cb.txd <= tr.header[15:8];
@(pkt_intf.cb);
pkt_intf.cb.txd <= tr.header[7:0];
foreach(tr.payload[i]) begin
@(pkt_intf.cb);
pkt_intf.cb.txd <= tr.payload[i];
end
delay = tr.payload.size() + 2;
repeat(delay) begin
@(pkt_intf.cb);
pkt_intf.cb.tx_vld <= 1'b0;
end
`vmm_callback(pkt_driver_callbacks, driver_post_tx(this, tr));
`vmm_debug(log, tr.psdisplay("Packet Driver ==>"));
end
endtask
task pkt_driver::reset();
@(pkt_intf.cb);
pkt_intf.cb.txd <= 8'h0;
pkt_intf.cb.tx_vld <= 1'b0;
@(pkt_intf.cb);
pkt_intf.rst_n = 1'b0;
@(pkt_intf.cb);
pkt_intf.rst_n = 1'b1;
@(pkt_intf.cb);
endtask
`endif
`define __PKT_DRIVER_SV__
`include "vmm.sv"
`include "pkt_interface.svi"
`include "pkt_trans.sv"
class pkt_driver extends vmm_xactor;
string name;
virtual pkt_interface.master pkt_intf;
pkt_trans_channel gen2drv_chan;
extern function new(
string instance,
integer stream_id = -1,
virtual pkt_interface.master pkt_intf,
pkt_trans_channel gen2drv_chan = null
);
extern virtual task main() ;
extern virtual task reset() ;
endclass
//callback class
virtual class pkt_driver_callbacks extends vmm_xactor_callbacks;
virtual task driver_pre_tx (
pkt_driver xactor,
ref pkt_trans trans,
ref bit drop
);
endtask
virtual task driver_post_tx (
pkt_driver xactor,
pkt_trans trans
);
endtask
endclass
function pkt_driver::new(
string instance,
integer stream_id = -1,
virtual pkt_interface.master pkt_intf,
pkt_trans_channel gen2drv_chan = null
);
super.new("Packet Driver", instance, stream_id) ;
this.pkt_intf = pkt_intf;
if(gen2drv_chan == null)
gen2drv_chan = new("Packet generator to driver channel", instance);
this.gen2drv_chan = gen2drv_chan;
endfunction
task pkt_driver::main();
integer delay = 0;
pkt_trans tr;
pkt_trans tr_cpy;
bit drop;
fork
super.main();
join_none
while (1) begin
this.wait_if_stopped_or_empty(this.gen2drv_chan) ;
gen2drv_chan.get(tr);
$cast(tr_cpy, tr.copy());
`vmm_callback(pkt_driver_callbacks, driver_pre_tx(this, tr_cpy, drop));
if (drop == 1) begin
`vmm_note(log, tr.psdisplay("Dropped"));
continue;
end
@(pkt_intf.cb);
pkt_intf.cb.tx_vld <= 1'b1;
pkt_intf.cb.txd <= tr.header[15:8];
@(pkt_intf.cb);
pkt_intf.cb.txd <= tr.header[7:0];
foreach(tr.payload[i]) begin
@(pkt_intf.cb);
pkt_intf.cb.txd <= tr.payload[i];
end
delay = tr.payload.size() + 2;
repeat(delay) begin
@(pkt_intf.cb);
pkt_intf.cb.tx_vld <= 1'b0;
end
`vmm_callback(pkt_driver_callbacks, driver_post_tx(this, tr));
`vmm_debug(log, tr.psdisplay("Packet Driver ==>"));
end
endtask
task pkt_driver::reset();
@(pkt_intf.cb);
pkt_intf.cb.txd <= 8'h0;
pkt_intf.cb.tx_vld <= 1'b0;
@(pkt_intf.cb);
pkt_intf.rst_n = 1'b0;
@(pkt_intf.cb);
pkt_intf.rst_n = 1'b1;
@(pkt_intf.cb);
endtask
`endif
//////////////////////////////////////////////////
//./env/packet_env/pkt_monitor.sv
//////////////////////////////////////////////////
`ifndef __PKT_MONITOR_SV__
`define __PKT_MONITOR_SV__
`include "vmm.sv"
`include "pkt_interface.svi"
`include "pkt_trans.sv"
class pkt_monitor extends vmm_xactor;
string name;
virtual pkt_interface.master pkt_intf;
extern function new(
string instance,
integer stream_id = -1,
virtual pkt_interface.master pkt_intf
);
extern virtual task main() ;
endclass
//callback class
virtual class pkt_monitor_callbacks extends vmm_xactor_callbacks;
virtual task monitor_pre_tx (
pkt_monitor xactor,
ref pkt_trans trans,
ref bit drop
);
endtask
virtual task monitor_post_tx (
pkt_monitor xactor,
pkt_trans trans
);
endtask
endclass
function pkt_monitor::new (
string instance,
integer stream_id = -1,
virtual pkt_interface.master pkt_intf
);
super.new("Packet Monitor", instance, stream_id) ;
this.pkt_intf = pkt_intf;
endfunction
task pkt_monitor::main();
logic [7:0] rxd[$];
logic [7:0] rxd_1[];
pkt_trans tr;
bit drop;
fork
super.main();
join_none
while (1) begin
tr = new();
`vmm_callback(pkt_monitor_callbacks, monitor_pre_tx(this, tr, drop));
if (drop == 1) begin
`vmm_note(log, tr.psdisplay("Dropped"));
continue;
end
@(pkt_intf.cb);
while(pkt_intf.cb.rx_vld == 1'b0) begin
@(pkt_intf.cb);
end
while(pkt_intf.cb.rx_vld == 1'b1) begin
rxd.push_back(pkt_intf.cb.rxd);
@(pkt_intf.cb);
end
rxd_1 = new[rxd.size()];
foreach(rxd[i]) begin
rxd_1[i] = rxd[i];
end
tr.byte_pack(rxd_1, 0);
rxd.delete();
rxd_1.delete();
`vmm_callback(pkt_monitor_callbacks, monitor_post_tx(this, tr));
`vmm_debug(log, tr.psdisplay("Packet monitor ==>"));
end
endtask
`endif
`define __PKT_MONITOR_SV__
`include "vmm.sv"
`include "pkt_interface.svi"
`include "pkt_trans.sv"
class pkt_monitor extends vmm_xactor;
string name;
virtual pkt_interface.master pkt_intf;
extern function new(
string instance,
integer stream_id = -1,
virtual pkt_interface.master pkt_intf
);
extern virtual task main() ;
endclass
//callback class
virtual class pkt_monitor_callbacks extends vmm_xactor_callbacks;
virtual task monitor_pre_tx (
pkt_monitor xactor,
ref pkt_trans trans,
ref bit drop
);
endtask
virtual task monitor_post_tx (
pkt_monitor xactor,
pkt_trans trans
);
endtask
endclass
function pkt_monitor::new (
string instance,
integer stream_id = -1,
virtual pkt_interface.master pkt_intf
);
super.new("Packet Monitor", instance, stream_id) ;
this.pkt_intf = pkt_intf;
endfunction
task pkt_monitor::main();
logic [7:0] rxd[$];
logic [7:0] rxd_1[];
pkt_trans tr;
bit drop;
fork
super.main();
join_none
while (1) begin
tr = new();
`vmm_callback(pkt_monitor_callbacks, monitor_pre_tx(this, tr, drop));
if (drop == 1) begin
`vmm_note(log, tr.psdisplay("Dropped"));
continue;
end
@(pkt_intf.cb);
while(pkt_intf.cb.rx_vld == 1'b0) begin
@(pkt_intf.cb);
end
while(pkt_intf.cb.rx_vld == 1'b1) begin
rxd.push_back(pkt_intf.cb.rxd);
@(pkt_intf.cb);
end
rxd_1 = new[rxd.size()];
foreach(rxd[i]) begin
rxd_1[i] = rxd[i];
end
tr.byte_pack(rxd_1, 0);
rxd.delete();
rxd_1.delete();
`vmm_callback(pkt_monitor_callbacks, monitor_post_tx(this, tr));
`vmm_debug(log, tr.psdisplay("Packet monitor ==>"));
end
endtask
`endif
//////////////////////////////////////////////////
//./env/packet_env/pkt_sb.sv
//////////////////////////////////////////////////
`ifndef __PKT_sb_SV__
`define __PKT_sb_SV__
`include "vmm.sv"
`include "vmm_sb.sv"
`include "pkt_trans.sv"
`include "pkt_driver.sv"
`include "pkt_monitor.sv"
class pkt_sb extends vmm_sb_ds;
logic [9:0] min_pkt_size;
logic [9:0] max_pkt_size;
extern function new();
extern virtual function bit compare(vmm_data actual, vmm_data expected);
extern function void report(int exp_stream_id = -1, int inp_stream_id = -1);
endclass
class pkt_driver_to_sb extends pkt_driver_callbacks;
pkt_sb pkt_scb;
function new(pkt_sb pkt_scb);
this.pkt_scb = pkt_scb;
endfunction: new
virtual task driver_pre_tx (pkt_driver xactor, ref pkt_trans trans, ref bit drop);
if(trans.pkt_head_type == pkt_trans::GOOD) begin
if(trans.payload.size() >= (pkt_scb.min_pkt_size - 2) && trans.payload.size() <= (pkt_scb.max_pkt_size - 2)) begin
pkt_scb.insert(trans, vmm_sb_ds::INPUT, .exp_stream_id(0));
end
end
endtask
endclass
class pkt_monitor_to_sb extends pkt_monitor_callbacks;
pkt_sb pkt_scb;
function new(pkt_sb pkt_scb);
this.pkt_scb = pkt_scb;
endfunction: new
virtual task monitor_post_tx (pkt_monitor xactor, pkt_trans trans);
pkt_scb.expect_in_order(trans, 0);
endtask
endclass
function pkt_sb::new();
super.new("Packet Scoreboard");
this.define_stream(0, "Master", INPUT);
this.define_stream(0, "Slave 0", EXPECT);
endfunction
function bit pkt_sb::compare(vmm_data actual, vmm_data expected);
pkt_trans act, exp;
string diff;
$cast(act, actual);
$cast(exp, expected);
return act.compare(exp, diff);
endfunction
function void pkt_sb::report(int exp_stream_id = -1, int inp_stream_id = -1);
super.report(exp_stream_id, inp_stream_id);
endfunction
`endif
`define __PKT_sb_SV__
`include "vmm.sv"
`include "vmm_sb.sv"
`include "pkt_trans.sv"
`include "pkt_driver.sv"
`include "pkt_monitor.sv"
class pkt_sb extends vmm_sb_ds;
logic [9:0] min_pkt_size;
logic [9:0] max_pkt_size;
extern function new();
extern virtual function bit compare(vmm_data actual, vmm_data expected);
extern function void report(int exp_stream_id = -1, int inp_stream_id = -1);
endclass
class pkt_driver_to_sb extends pkt_driver_callbacks;
pkt_sb pkt_scb;
function new(pkt_sb pkt_scb);
this.pkt_scb = pkt_scb;
endfunction: new
virtual task driver_pre_tx (pkt_driver xactor, ref pkt_trans trans, ref bit drop);
if(trans.pkt_head_type == pkt_trans::GOOD) begin
if(trans.payload.size() >= (pkt_scb.min_pkt_size - 2) && trans.payload.size() <= (pkt_scb.max_pkt_size - 2)) begin
pkt_scb.insert(trans, vmm_sb_ds::INPUT, .exp_stream_id(0));
end
end
endtask
endclass
class pkt_monitor_to_sb extends pkt_monitor_callbacks;
pkt_sb pkt_scb;
function new(pkt_sb pkt_scb);
this.pkt_scb = pkt_scb;
endfunction: new
virtual task monitor_post_tx (pkt_monitor xactor, pkt_trans trans);
pkt_scb.expect_in_order(trans, 0);
endtask
endclass
function pkt_sb::new();
super.new("Packet Scoreboard");
this.define_stream(0, "Master", INPUT);
this.define_stream(0, "Slave 0", EXPECT);
endfunction
function bit pkt_sb::compare(vmm_data actual, vmm_data expected);
pkt_trans act, exp;
string diff;
$cast(act, actual);
$cast(exp, expected);
return act.compare(exp, diff);
endfunction
function void pkt_sb::report(int exp_stream_id = -1, int inp_stream_id = -1);
super.report(exp_stream_id, inp_stream_id);
endfunction
`endif
//////////////////////////////////////////////////
//./env/packet_env/pkt_env.sv
//////////////////////////////////////////////////
`ifndef __PKT_ENV_SV__
`define __PKT_ENV_SV__
`include "pkt_interface.svi"
`include "pkt_trans.sv"
`include "pkt_driver.sv"
`include "pkt_sb.sv"
`include "pkt_monitor.sv"
class pkt_env extends vmm_env;
virtual pkt_interface.master pkt_intf;
vmm_log log;
pkt_trans_channel gen2drv_chan;
pkt_trans_atomic_gen pkt_gen;
pkt_driver pkt_drv;
pkt_sb pkt_scb;
pkt_monitor pkt_mon;
pkt_driver_to_sb pkt_drv_cbs_scb;
pkt_monitor_to_sb pkt_mon_cbs_scb;
extern function new(virtual pkt_interface.master pkt_intf);
extern virtual function void gen_cfg();
extern virtual function void build();
extern virtual task reset_dut();
extern virtual task cfg_dut();
extern virtual task start();
extern virtual task wait_for_end();
extern virtual task stop();
extern virtual task cleanup();
extern virtual task report();
endclass
function pkt_env::new(virtual pkt_interface.master pkt_intf);
super.new("Packet ENV");
this.pkt_intf = pkt_intf;
log = new("packet", "env");
endfunction
function void pkt_env::gen_cfg();
super.gen_cfg();
endfunction
function void pkt_env::build();
super.build();
gen2drv_chan = new("Packet Generator to Driver Channel", "channel");
pkt_gen = new("Packet Generator", 1, gen2drv_chan);
pkt_drv = new("Packet Driver", 1, pkt_intf, gen2drv_chan);
pkt_mon = new("Packet Monitor", 1, pkt_intf);
pkt_scb = new();
pkt_drv_cbs_scb = new(pkt_scb);
pkt_drv.append_callback(pkt_drv_cbs_scb);
pkt_mon_cbs_scb = new(pkt_scb);
pkt_mon.append_callback(pkt_mon_cbs_scb);
endfunction
task pkt_env::reset_dut();
super.reset_dut();
pkt_drv.reset();
endtask
task pkt_env::cfg_dut();
super.cfg_dut();
endtask
task pkt_env::start();
super.start();
pkt_gen.start_xactor();
pkt_drv.start_xactor();
pkt_mon.start_xactor();
endtask
task pkt_env::wait_for_end();
super.wait_for_end();
fork
pkt_gen.notify.wait_for(pkt_trans_atomic_gen::DONE);
join_any
endtask
task pkt_env::stop();
super.stop();
pkt_gen.stop_xactor();
pkt_drv.stop_xactor();
pkt_mon.stop_xactor();
endtask
task pkt_env::cleanup();
super.cleanup();
endtask
task pkt_env::report();
super.report();
endtask
`endif
`define __PKT_ENV_SV__
`include "pkt_interface.svi"
`include "pkt_trans.sv"
`include "pkt_driver.sv"
`include "pkt_sb.sv"
`include "pkt_monitor.sv"
class pkt_env extends vmm_env;
virtual pkt_interface.master pkt_intf;
vmm_log log;
pkt_trans_channel gen2drv_chan;
pkt_trans_atomic_gen pkt_gen;
pkt_driver pkt_drv;
pkt_sb pkt_scb;
pkt_monitor pkt_mon;
pkt_driver_to_sb pkt_drv_cbs_scb;
pkt_monitor_to_sb pkt_mon_cbs_scb;
extern function new(virtual pkt_interface.master pkt_intf);
extern virtual function void gen_cfg();
extern virtual function void build();
extern virtual task reset_dut();
extern virtual task cfg_dut();
extern virtual task start();
extern virtual task wait_for_end();
extern virtual task stop();
extern virtual task cleanup();
extern virtual task report();
endclass
function pkt_env::new(virtual pkt_interface.master pkt_intf);
super.new("Packet ENV");
this.pkt_intf = pkt_intf;
log = new("packet", "env");
endfunction
function void pkt_env::gen_cfg();
super.gen_cfg();
endfunction
function void pkt_env::build();
super.build();
gen2drv_chan = new("Packet Generator to Driver Channel", "channel");
pkt_gen = new("Packet Generator", 1, gen2drv_chan);
pkt_drv = new("Packet Driver", 1, pkt_intf, gen2drv_chan);
pkt_mon = new("Packet Monitor", 1, pkt_intf);
pkt_scb = new();
pkt_drv_cbs_scb = new(pkt_scb);
pkt_drv.append_callback(pkt_drv_cbs_scb);
pkt_mon_cbs_scb = new(pkt_scb);
pkt_mon.append_callback(pkt_mon_cbs_scb);
endfunction
task pkt_env::reset_dut();
super.reset_dut();
pkt_drv.reset();
endtask
task pkt_env::cfg_dut();
super.cfg_dut();
endtask
task pkt_env::start();
super.start();
pkt_gen.start_xactor();
pkt_drv.start_xactor();
pkt_mon.start_xactor();
endtask
task pkt_env::wait_for_end();
super.wait_for_end();
fork
pkt_gen.notify.wait_for(pkt_trans_atomic_gen::DONE);
join_any
endtask
task pkt_env::stop();
super.stop();
pkt_gen.stop_xactor();
pkt_drv.stop_xactor();
pkt_mon.stop_xactor();
endtask
task pkt_env::cleanup();
super.cleanup();
endtask
task pkt_env::report();
super.report();
endtask
`endif
//////////////////////////////////////////////////
//./env/env.sv
//////////////////////////////////////////////////
`ifndef __ENV_SV__
`define __ENV_SV__
`include "cpu_interface.svi"
`include "pkt_interface.svi"
`include "cpu_env.sv"
`include "pkt_env.sv"
class env extends vmm_env;
vmm_log log;
cpu_env cpu_e;
pkt_env pkt_e;
extern function new(virtual cpu_interface.master cpu_intf, virtual pkt_interface.master pkt_intf);
extern virtual function void gen_cfg();
extern virtual function void build();
extern virtual task reset_dut();
extern virtual task cfg_dut();
extern virtual task start();
extern virtual task wait_for_end();
extern virtual task stop();
extern virtual task cleanup();
extern virtual task report();
endclass
function env::new(virtual cpu_interface.master cpu_intf, virtual pkt_interface.master pkt_intf);
super.new("Packet ENV");
cpu_e = new(cpu_intf);
pkt_e = new(pkt_intf);
log = new("env", "env");
endfunction
function void env::gen_cfg();
super.gen_cfg();
endfunction
function void env::build();
super.build();
cpu_e.build();
pkt_e.build();
endfunction
task env::reset_dut();
super.reset_dut();
cpu_e.reset_dut();
pkt_e.reset_dut();
endtask
task env::cfg_dut();
super.cfg_dut();
endtask
task env::start();
super.start();
cpu_e.start();
pkt_e.start();
endtask
task env::wait_for_end();
super.wait_for_end();
cpu_e.wait_for_end();
pkt_e.wait_for_end();
endtask
task env::stop();
super.stop();
cpu_e.stop();
pkt_e.stop();
endtask
task env::cleanup();
super.cleanup();
endtask
task env::report();
super.report();
endtask
`endif
`define __ENV_SV__
`include "cpu_interface.svi"
`include "pkt_interface.svi"
`include "cpu_env.sv"
`include "pkt_env.sv"
class env extends vmm_env;
vmm_log log;
cpu_env cpu_e;
pkt_env pkt_e;
extern function new(virtual cpu_interface.master cpu_intf, virtual pkt_interface.master pkt_intf);
extern virtual function void gen_cfg();
extern virtual function void build();
extern virtual task reset_dut();
extern virtual task cfg_dut();
extern virtual task start();
extern virtual task wait_for_end();
extern virtual task stop();
extern virtual task cleanup();
extern virtual task report();
endclass
function env::new(virtual cpu_interface.master cpu_intf, virtual pkt_interface.master pkt_intf);
super.new("Packet ENV");
cpu_e = new(cpu_intf);
pkt_e = new(pkt_intf);
log = new("env", "env");
endfunction
function void env::gen_cfg();
super.gen_cfg();
endfunction
function void env::build();
super.build();
cpu_e.build();
pkt_e.build();
endfunction
task env::reset_dut();
super.reset_dut();
cpu_e.reset_dut();
pkt_e.reset_dut();
endtask
task env::cfg_dut();
super.cfg_dut();
endtask
task env::start();
super.start();
cpu_e.start();
pkt_e.start();
endtask
task env::wait_for_end();
super.wait_for_end();
cpu_e.wait_for_end();
pkt_e.wait_for_end();
endtask
task env::stop();
super.stop();
cpu_e.stop();
pkt_e.stop();
endtask
task env::cleanup();
super.cleanup();
endtask
task env::report();
super.report();
endtask
`endif
//////////////////////////////////////////////////
//./test/test.sv
//////////////////////////////////////////////////
`ifndef __TEST_SV__
`define __TEST_SV__
`include "env.sv"
program test(cpu_interface.master cpu_intf, pkt_interface.master pkt_intf);
class pkt_trans_ext extends pkt_trans;
//constraint con_pkt_len_test {
// payload.size() == 100;
// pkt_head_type == GOOD;
//}
endclass
cpu_trans cpu_tr;
cpu_trans cpu_tr_cpy;
pkt_trans_ext pkt_tr;
env e;
initial begin
cpu_tr = new();
pkt_tr = new();
e = new(cpu_intf, pkt_intf);
e.build();
//if stop_after_n_insts is 0, the generator will generate transaction forever
//e.cpu_e.cpu_gen.stop_after_n_insts = 0;
e.pkt_e.pkt_gen.randomized_obj = pkt_tr;
e.start();
e.cpu_e.cpu_gen.stop_xactor();
e.pkt_e.pkt_gen.stop_xactor();
cpu_tr.randomize() with {addr == 'h4; rw == 1'b0; dout == 'd65;};
$cast(cpu_tr_cpy, cpu_tr.copy());
e.cpu_e.gen2drv_chan.put(cpu_tr_cpy);
cpu_tr.randomize() with {addr == 'h8; rw == 1'b0; dout == 'd500;};
$cast(cpu_tr_cpy, cpu_tr.copy());
e.cpu_e.gen2drv_chan.put(cpu_tr_cpy);
cpu_tr.randomize() with {addr == 'h0; rw == 1'b0; dout == 'h1;};
$cast(cpu_tr_cpy, cpu_tr.copy());
e.cpu_e.gen2drv_chan.put(cpu_tr_cpy);
repeat(100) begin
@(cpu_intf.cb);
end
e.pkt_e.pkt_scb.min_pkt_size = 65;
e.pkt_e.pkt_scb.max_pkt_size = 500;
e.pkt_e.pkt_gen.stop_after_n_insts = 100;
e.pkt_e.pkt_gen.start_xactor();
e.pkt_e.wait_for_end();
repeat(10000) begin
@(pkt_intf.cb);
end
e.report();
$finish();
end
endprogram
`endif
`define __TEST_SV__
`include "env.sv"
program test(cpu_interface.master cpu_intf, pkt_interface.master pkt_intf);
class pkt_trans_ext extends pkt_trans;
//constraint con_pkt_len_test {
// payload.size() == 100;
// pkt_head_type == GOOD;
//}
endclass
cpu_trans cpu_tr;
cpu_trans cpu_tr_cpy;
pkt_trans_ext pkt_tr;
env e;
initial begin
cpu_tr = new();
pkt_tr = new();
e = new(cpu_intf, pkt_intf);
e.build();
//if stop_after_n_insts is 0, the generator will generate transaction forever
//e.cpu_e.cpu_gen.stop_after_n_insts = 0;
e.pkt_e.pkt_gen.randomized_obj = pkt_tr;
e.start();
e.cpu_e.cpu_gen.stop_xactor();
e.pkt_e.pkt_gen.stop_xactor();
cpu_tr.randomize() with {addr == 'h4; rw == 1'b0; dout == 'd65;};
$cast(cpu_tr_cpy, cpu_tr.copy());
e.cpu_e.gen2drv_chan.put(cpu_tr_cpy);
cpu_tr.randomize() with {addr == 'h8; rw == 1'b0; dout == 'd500;};
$cast(cpu_tr_cpy, cpu_tr.copy());
e.cpu_e.gen2drv_chan.put(cpu_tr_cpy);
cpu_tr.randomize() with {addr == 'h0; rw == 1'b0; dout == 'h1;};
$cast(cpu_tr_cpy, cpu_tr.copy());
e.cpu_e.gen2drv_chan.put(cpu_tr_cpy);
repeat(100) begin
@(cpu_intf.cb);
end
e.pkt_e.pkt_scb.min_pkt_size = 65;
e.pkt_e.pkt_scb.max_pkt_size = 500;
e.pkt_e.pkt_gen.stop_after_n_insts = 100;
e.pkt_e.pkt_gen.start_xactor();
e.pkt_e.wait_for_end();
repeat(10000) begin
@(pkt_intf.cb);
end
e.report();
$finish();
end
endprogram
`endif
//////////////////////////////////////////////////
//./env/top.sv
//////////////////////////////////////////////////
`timescale 1ns/1ps
`include "cpu_interface.svi"
`include "pkt_interface.svi"
`include "test.sv"
module top;
parameter clock_cycle = 10;
logic clk;
cpu_interface cpu_intf(clk);
pkt_interface pkt_intf(clk);
test u_test(cpu_intf, pkt_intf);
dut u_dut (
.clk (pkt_intf.clk ) ,
.rst_n (pkt_intf.rst_n ) ,
.addr (cpu_intf.addr ) ,
.rw (cpu_intf.rw ) ,
.din (cpu_intf.dout ) ,
.dout (cpu_intf.din ) ,
.txd (pkt_intf.rxd ) ,
.tx_vld (pkt_intf.rx_vld ) ,
.rxd (pkt_intf.txd ) ,
.rx_vld (pkt_intf.tx_vld )
);
initial begin
$timeformat(-9, 1, "ns", 10);
clk = 0;
forever begin
#(clock_cycle/2) clk = ~clk;
end
end
`ifdef WAVE_ON
initial begin
$vcdpluson();
end
`endif
endmodule
`include "cpu_interface.svi"
`include "pkt_interface.svi"
`include "test.sv"
module top;
parameter clock_cycle = 10;
logic clk;
cpu_interface cpu_intf(clk);
pkt_interface pkt_intf(clk);
test u_test(cpu_intf, pkt_intf);
dut u_dut (
.clk (pkt_intf.clk ) ,
.rst_n (pkt_intf.rst_n ) ,
.addr (cpu_intf.addr ) ,
.rw (cpu_intf.rw ) ,
.din (cpu_intf.dout ) ,
.dout (cpu_intf.din ) ,
.txd (pkt_intf.rxd ) ,
.tx_vld (pkt_intf.rx_vld ) ,
.rxd (pkt_intf.txd ) ,
.rx_vld (pkt_intf.tx_vld )
);
initial begin
$timeformat(-9, 1, "ns", 10);
clk = 0;
forever begin
#(clock_cycle/2) clk = ~clk;
end
end
`ifdef WAVE_ON
initial begin
$vcdpluson();
end
`endif
endmodule
##################################################
#./script/Makefile
##################################################
ifeq ($(GUI), 1)
GUI_ARG = -gui
endif
PROJECT_DIR = /mnt/vmm
RTL_DIR = $(PROJECT_DIR)/rtl
RTL = $(RTL_DIR)/dut.v
TB_DIR = $(PROJECT_DIR)/env
INCDIR = +incdir+$(TB_DIR)
CPU_INTF_TB_DIR = $(TB_DIR)/cpu_interface_env
INCDIR += +incdir+$(CPU_INTF_TB_DIR)
PKT_TB_DIR = $(TB_DIR)/packet_env
INCDIR += +incdir+$(PKT_TB_DIR)
VMM_TB = $(TB_DIR)/env.sv $(TB_DIR)/top.sv
TEST_DIR = $(PROJECT_DIR)/test
TEST_FILE = $(TEST_DIR)/test.sv
INCDIR += +incdir+$(TEST_DIR)
VMM_ARG = -ntb -ntb_opts rvm
COMPILE_LOG_ARG = -l vcs.log
WAVE_ARG = +define+WAVE_ON=1
COMPILE_ARG = -sverilog -debug_all
COMPILE_ARG += $(INCDIR) $(COMPILE_LOG_ARG) $(WAVE_ARG) $(VMM_ARG)
RUN_LOG_ARG = -l simv.log
RUN_ARG =
RUN_ARG += $(RUN_LOG_ARG) $(GUI_ARG)
SEED = 1
default: test
test: compile run
run:
./simv $(RUN_ARG) +ntb_random_seed=$(SEED)
compile:
vcs $(COMPILE_ARG) $(RTL) $(VMM_TB) $(TEST_FILE)
clean:
rm -rf simv simv.* *log
GUI_ARG = -gui
endif
PROJECT_DIR = /mnt/vmm
RTL_DIR = $(PROJECT_DIR)/rtl
RTL = $(RTL_DIR)/dut.v
TB_DIR = $(PROJECT_DIR)/env
INCDIR = +incdir+$(TB_DIR)
CPU_INTF_TB_DIR = $(TB_DIR)/cpu_interface_env
INCDIR += +incdir+$(CPU_INTF_TB_DIR)
PKT_TB_DIR = $(TB_DIR)/packet_env
INCDIR += +incdir+$(PKT_TB_DIR)
VMM_TB = $(TB_DIR)/env.sv $(TB_DIR)/top.sv
TEST_DIR = $(PROJECT_DIR)/test
TEST_FILE = $(TEST_DIR)/test.sv
INCDIR += +incdir+$(TEST_DIR)
VMM_ARG = -ntb -ntb_opts rvm
COMPILE_LOG_ARG = -l vcs.log
WAVE_ARG = +define+WAVE_ON=1
COMPILE_ARG = -sverilog -debug_all
COMPILE_ARG += $(INCDIR) $(COMPILE_LOG_ARG) $(WAVE_ARG) $(VMM_ARG)
RUN_LOG_ARG = -l simv.log
RUN_ARG =
RUN_ARG += $(RUN_LOG_ARG) $(GUI_ARG)
SEED = 1
default: test
test: compile run
run:
./simv $(RUN_ARG) +ntb_random_seed=$(SEED)
compile:
vcs $(COMPILE_ARG) $(RTL) $(VMM_TB) $(TEST_FILE)
clean:
rm -rf simv simv.* *log