// ./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 [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;
mem[mem_wr_ptr] <= rxd;
if(rxd != 8'h55) begin
pkt_recv_status <= `PKT_RECV_END;
end
else begin
pkt_recv_status <= `PKT_RECV_START;
end
end
end
`PKT_RECV_START: begin
if(rx_vld == 1'b1) begin
mem_wr_ptr <= mem_wr_ptr + 1;
mem[mem_wr_ptr] <= rxd;
if(rxd != 8'hd5) begin
pkt_recv_status <= `PKT_RECV_END;
end
else begin
pkt_recv_status <= `PKT_RECV_RECV;
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) 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 [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;
mem[mem_wr_ptr] <= rxd;
if(rxd != 8'h55) begin
pkt_recv_status <= `PKT_RECV_END;
end
else begin
pkt_recv_status <= `PKT_RECV_START;
end
end
end
`PKT_RECV_START: begin
if(rx_vld == 1'b1) begin
mem_wr_ptr <= mem_wr_ptr + 1;
mem[mem_wr_ptr] <= rxd;
if(rxd != 8'hd5) begin
pkt_recv_status <= `PKT_RECV_END;
end
else begin
pkt_recv_status <= `PKT_RECV_RECV;
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) 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/transactor.sv
//////////////////////////////////////////////////
`ifndef __TRANSACTOR_SV__
`define __TRANSACTOR_SV__
`include "transactor_callback.sv"
class transactor;
transactor_callback callbacks[$];
function new();
endfunction
virtual function bit prepend_callback(transactor_callback cb);
foreach (this.callbacks[i]) begin
if (this.callbacks[i] == cb) begin
return 1;
end
end
this.callbacks.push_front(cb);
return 0;
endfunction
virtual function bit append_callback(transactor_callback cb);
foreach (this.callbacks[i]) begin
if (this.callbacks[i] == cb) begin
return 1;
end
end
this.callbacks.push_back(cb);
return 0;
endfunction
virtual function bit unregister_callback(transactor_callback cb);
foreach (this.callbacks[i]) begin
if(cb == callbacks[i]) begin
callbacks.delete(i);
return 0;
end
end
return 1;
endfunction
endclass
`endif
`define __TRANSACTOR_SV__
`include "transactor_callback.sv"
class transactor;
transactor_callback callbacks[$];
function new();
endfunction
virtual function bit prepend_callback(transactor_callback cb);
foreach (this.callbacks[i]) begin
if (this.callbacks[i] == cb) begin
return 1;
end
end
this.callbacks.push_front(cb);
return 0;
endfunction
virtual function bit append_callback(transactor_callback cb);
foreach (this.callbacks[i]) begin
if (this.callbacks[i] == cb) begin
return 1;
end
end
this.callbacks.push_back(cb);
return 0;
endfunction
virtual function bit unregister_callback(transactor_callback cb);
foreach (this.callbacks[i]) begin
if(cb == callbacks[i]) begin
callbacks.delete(i);
return 0;
end
end
return 1;
endfunction
endclass
`endif
//////////////////////////////////////////////////
// ./env/transactor_callback.sv
//////////////////////////////////////////////////
`ifndef __TRANSACTOR_CALLBACK_SV__
`define __TRANSACTOR_CALLBACK_SV__
`define callback_macro(facade, call) foreach(this.callbacks[i]) begin facade cb; if(!$cast(cb, this.callbacks[i])) continue; cb.call; end
virtual class transactor_callback;
endclass
`endif
`define __TRANSACTOR_CALLBACK_SV__
`define callback_macro(facade, call) foreach(this.callbacks[i]) begin facade cb; if(!$cast(cb, this.callbacks[i])) continue; cb.call; end
virtual class transactor_callback;
endclass
`endif
//////////////////////////////////////////////////
// ./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_transaction.sv
//////////////////////////////////////////////////
`ifndef __CPU_TRANSACTION_SV__
`define __CPU_TRANSACTION_SV__
class cpu_transaction;
string name;
rand logic [7:0] addr;
rand logic rw;
rand logic [31:0] dout;
logic [31:0] din = 32'h0;
extern function new(string name = "CPU Transaction");
extern function cpu_transaction copy();
extern function void display(string prefix = "Note");
endclass
function cpu_transaction::new(string name);
this.name = name;
endfunction
function cpu_transaction cpu_transaction::copy();
cpu_transaction cpu_tran_cpy = new();
cpu_tran_cpy.addr = addr;
cpu_tran_cpy.rw = rw;
cpu_tran_cpy.dout = dout;
cpu_tran_cpy.din = din;
return cpu_tran_cpy;
endfunction
function void cpu_transaction::display(string prefix);
$display("[%s]%t %s addr = %0h, dout = %0h, rw = %d, din = %0h", prefix, $realtime, name, addr, dout, rw, din);
endfunction
`endif
`define __CPU_TRANSACTION_SV__
class cpu_transaction;
string name;
rand logic [7:0] addr;
rand logic rw;
rand logic [31:0] dout;
logic [31:0] din = 32'h0;
extern function new(string name = "CPU Transaction");
extern function cpu_transaction copy();
extern function void display(string prefix = "Note");
endclass
function cpu_transaction::new(string name);
this.name = name;
endfunction
function cpu_transaction cpu_transaction::copy();
cpu_transaction cpu_tran_cpy = new();
cpu_tran_cpy.addr = addr;
cpu_tran_cpy.rw = rw;
cpu_tran_cpy.dout = dout;
cpu_tran_cpy.din = din;
return cpu_tran_cpy;
endfunction
function void cpu_transaction::display(string prefix);
$display("[%s]%t %s addr = %0h, dout = %0h, rw = %d, din = %0h", prefix, $realtime, name, addr, dout, rw, din);
endfunction
`endif
//////////////////////////////////////////////////
// ./env/cpu_interface_env/cpu_define.sv
//////////////////////////////////////////////////
`ifndef __CPU_DEFINE_SV__
`define __CPU_DEFINE_SV__
typedef class cpu_transaction;
typedef mailbox #(cpu_transaction) cpu_tran_mbox;
`endif
`define __CPU_DEFINE_SV__
typedef class cpu_transaction;
typedef mailbox #(cpu_transaction) cpu_tran_mbox;
`endif
//////////////////////////////////////////////////
// ./env/cpu_interface_env/cpu_generator.sv
//////////////////////////////////////////////////
`ifndef __CPU_GENERATOR_SV__
`define __CPU_GENERATOR_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
class cpu_generator;
string name;
cpu_tran_mbox out_box;
int run_for_n_trans = 0;
cpu_transaction cpu_tran;
event done;
extern function new(string name = "CPU Generator", cpu_tran_mbox out_box);
extern task start();
endclass
function cpu_generator::new(string name, cpu_tran_mbox out_box);
this.name = name;
this.out_box = out_box;
endfunction
task cpu_generator::start();
fork
begin
for(int i=0; i
cpu_transaction cpu_tran_cpy = new cpu_tran;
if(!cpu_tran_cpy.randomize()) begin
$display("Error to randomize cpu_tran_cpy");
end
out_box.put(cpu_tran_cpy);
end
->done;
end
join_none
endtask
`endif
`define __CPU_GENERATOR_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
class cpu_generator;
string name;
cpu_tran_mbox out_box;
int run_for_n_trans = 0;
cpu_transaction cpu_tran;
event done;
extern function new(string name = "CPU Generator", cpu_tran_mbox out_box);
extern task start();
endclass
function cpu_generator::new(string name, cpu_tran_mbox out_box);
this.name = name;
this.out_box = out_box;
endfunction
task cpu_generator::start();
fork
begin
for(int i=0; i
if(!cpu_tran_cpy.randomize()) begin
$display("Error to randomize cpu_tran_cpy");
end
out_box.put(cpu_tran_cpy);
end
->done;
end
join_none
endtask
`endif
//////////////////////////////////////////////////
// ./env/cpu_interface_env/cpu_driver.sv
//////////////////////////////////////////////////
`ifndef __CPU_DRIVER_SV__
`define __CPU_DRIVER_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
`include "cpu_interface.svi"
`include "transactor_callback.sv"
`include "transactor.sv"
class cpu_driver extends transactor;
string name;
cpu_tran_mbox in_box;
virtual cpu_interface.master cpu_intf;
extern function new(string name = "CPU Driver", cpu_tran_mbox in_box, virtual cpu_interface.master cpu_intf);
extern task start();
endclass
class cpu_driver_callback extends transactor_callback;
virtual task driver_pre_transactor (cpu_driver xactor, ref cpu_transaction cpu_tr, ref bit drop);
endtask
virtual task driver_post_transactor (cpu_driver xactor, ref cpu_transaction cpu_tr);
endtask
endclass
function cpu_driver::new(string name, cpu_tran_mbox in_box, virtual cpu_interface.master cpu_intf);
super.new();
this.name = name;
this.in_box = in_box;
this.cpu_intf = cpu_intf;
endfunction
task cpu_driver::start();
fork
forever begin
cpu_transaction cpu_tran;
in_box.get(cpu_tran);
cpu_tran.display();
@(cpu_intf.cb);
cpu_intf.cb.addr <= cpu_tran.addr;
cpu_intf.cb.dout <= cpu_tran.dout;
cpu_intf.cb.rw <= cpu_tran.rw;
if(cpu_tran.rw == 1'b1) begin
@(cpu_intf.cb);
cpu_tran.din = cpu_intf.cb.din;
end
`callback_macro(cpu_driver_callback, driver_post_transactor(this, cpu_tran))
end
join_none
endtask
`endif
`define __CPU_DRIVER_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
`include "cpu_interface.svi"
`include "transactor_callback.sv"
`include "transactor.sv"
class cpu_driver extends transactor;
string name;
cpu_tran_mbox in_box;
virtual cpu_interface.master cpu_intf;
extern function new(string name = "CPU Driver", cpu_tran_mbox in_box, virtual cpu_interface.master cpu_intf);
extern task start();
endclass
class cpu_driver_callback extends transactor_callback;
virtual task driver_pre_transactor (cpu_driver xactor, ref cpu_transaction cpu_tr, ref bit drop);
endtask
virtual task driver_post_transactor (cpu_driver xactor, ref cpu_transaction cpu_tr);
endtask
endclass
function cpu_driver::new(string name, cpu_tran_mbox in_box, virtual cpu_interface.master cpu_intf);
super.new();
this.name = name;
this.in_box = in_box;
this.cpu_intf = cpu_intf;
endfunction
task cpu_driver::start();
fork
forever begin
cpu_transaction cpu_tran;
in_box.get(cpu_tran);
cpu_tran.display();
@(cpu_intf.cb);
cpu_intf.cb.addr <= cpu_tran.addr;
cpu_intf.cb.dout <= cpu_tran.dout;
cpu_intf.cb.rw <= cpu_tran.rw;
if(cpu_tran.rw == 1'b1) begin
@(cpu_intf.cb);
cpu_tran.din = cpu_intf.cb.din;
end
`callback_macro(cpu_driver_callback, driver_post_transactor(this, cpu_tran))
end
join_none
endtask
`endif
//////////////////////////////////////////////////
// ./env/cpu_interface_env/cpu_scoreboard.sv
//////////////////////////////////////////////////
`ifndef __CPU_SCOREBOARD_SV__
`define __CPU_SCOREBOARD_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
`include "cpu_driver.sv"
class cpu_scoreboard;
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 function bit compare(cpu_transaction data);
extern function display(string prefix = "CPU Scoreboard Result");
endclass
class cpu_driver_sb_callback extends cpu_driver_callback;
cpu_scoreboard cpu_sb;
function new(cpu_scoreboard cpu_sb);
this.cpu_sb = cpu_sb;
endfunction
virtual task driver_post_transactor(cpu_driver xactor, ref cpu_transaction cpu_tr);
cpu_sb.compare(cpu_tr);
endtask
endclass
function cpu_scoreboard::new(string name);
this.name = name;
for(int i=0; i<128 data-blogger-escaped-begin="" data-blogger-escaped-br="" data-blogger-escaped-i=""> cpu_reg[i] = 32'h0;
end
endfunction
function bit cpu_scoreboard::compare(cpu_transaction data);
cpu_transaction 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_scoreboard::display(string prefix);
$display("Total: %d, Error: %d", total_no, error_no);
endfunction
`endif
`define __CPU_SCOREBOARD_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
`include "cpu_driver.sv"
class cpu_scoreboard;
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 function bit compare(cpu_transaction data);
extern function display(string prefix = "CPU Scoreboard Result");
endclass
class cpu_driver_sb_callback extends cpu_driver_callback;
cpu_scoreboard cpu_sb;
function new(cpu_scoreboard cpu_sb);
this.cpu_sb = cpu_sb;
endfunction
virtual task driver_post_transactor(cpu_driver xactor, ref cpu_transaction cpu_tr);
cpu_sb.compare(cpu_tr);
endtask
endclass
function cpu_scoreboard::new(string name);
this.name = name;
for(int i=0; i<128 data-blogger-escaped-begin="" data-blogger-escaped-br="" data-blogger-escaped-i=""> cpu_reg[i] = 32'h0;
end
endfunction
function bit cpu_scoreboard::compare(cpu_transaction data);
cpu_transaction 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_scoreboard::display(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_transaction.sv"
`include "cpu_generator.sv"
`include "cpu_define.sv"
`include "cpu_driver.sv"
`include "cpu_scoreboard.sv"
class cpu_env;
cpu_tran_mbox drv_mbox = new(1);
cpu_generator cpu_gen;
cpu_driver cpu_drv;
cpu_scoreboard cpu_sb;
cpu_driver_sb_callback cpu_drv_cbs_scb;
virtual cpu_interface.master cpu_intf;
extern function new(virtual cpu_interface.master cpu_intf);
extern function configure();
extern task reset();
extern task start();
extern function report();
endclass
function cpu_env::new(virtual cpu_interface.master cpu_intf);
this.cpu_intf = cpu_intf;
cpu_gen = new("CPU Generator", drv_mbox);
cpu_drv = new("CPU Driver", drv_mbox, cpu_intf);
cpu_sb = new("CPU Scoreboard");
cpu_drv_cbs_scb = new(cpu_sb);
cpu_drv.append_callback(cpu_drv_cbs_scb);
endfunction
function cpu_env::configure();
endfunction
task cpu_env::reset();
cpu_intf.cb.addr <= 8'h0;
cpu_intf.cb.rw <= 1'b1;
cpu_intf.cb.dout <= 31'h0;
@(cpu_intf.cb);
cpu_intf.rst_n = 1'b0;
@(cpu_intf.cb);
cpu_intf.rst_n = 1'b1;
@(cpu_intf.cb);
endtask
task cpu_env::start();
cpu_gen.start();
cpu_drv.start();
endtask
function cpu_env::report();
cpu_sb.display();
endfunction
`endif
`define __CPU_ENV_SV__
`include "cpu_interface.svi"
`include "cpu_transaction.sv"
`include "cpu_generator.sv"
`include "cpu_define.sv"
`include "cpu_driver.sv"
`include "cpu_scoreboard.sv"
class cpu_env;
cpu_tran_mbox drv_mbox = new(1);
cpu_generator cpu_gen;
cpu_driver cpu_drv;
cpu_scoreboard cpu_sb;
cpu_driver_sb_callback cpu_drv_cbs_scb;
virtual cpu_interface.master cpu_intf;
extern function new(virtual cpu_interface.master cpu_intf);
extern function configure();
extern task reset();
extern task start();
extern function report();
endclass
function cpu_env::new(virtual cpu_interface.master cpu_intf);
this.cpu_intf = cpu_intf;
cpu_gen = new("CPU Generator", drv_mbox);
cpu_drv = new("CPU Driver", drv_mbox, cpu_intf);
cpu_sb = new("CPU Scoreboard");
cpu_drv_cbs_scb = new(cpu_sb);
cpu_drv.append_callback(cpu_drv_cbs_scb);
endfunction
function cpu_env::configure();
endfunction
task cpu_env::reset();
cpu_intf.cb.addr <= 8'h0;
cpu_intf.cb.rw <= 1'b1;
cpu_intf.cb.dout <= 31'h0;
@(cpu_intf.cb);
cpu_intf.rst_n = 1'b0;
@(cpu_intf.cb);
cpu_intf.rst_n = 1'b1;
@(cpu_intf.cb);
endtask
task cpu_env::start();
cpu_gen.start();
cpu_drv.start();
endtask
function cpu_env::report();
cpu_sb.display();
endfunction
`endif
//////////////////////////////////////////////////
// ./env/packet_env/packet_interface.svi
//////////////////////////////////////////////////
`ifndef __PACKET_INTERFACE_SVI__
`define __PACKET_INTERFACE_SVI__
interface packet_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 __PACKET_INTERFACE_SVI__
interface packet_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/packet_transaction.sv
//////////////////////////////////////////////////
`ifndef __PACKET_TRANSACTION_SV__
`define __PACKET_TRANSACTION_SV__
class packet_transaction;
string name;
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[$] ;
rand logic [6:0 ] frame_interval;
extern function new(string name = "Packet Transaction");
extern function void display(string prefix = "Note");
extern function bit compare(packet_transaction pkt2cmp, ref string message);
extern function void byte2pkt(ref logic[7:0] data[$]);
extern function packet_transaction copy();
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]});
}
constraint con_frame_interval {
frame_interval inside {[96:200]};
}
endclass
function packet_transaction::new(string name);
this.name = name;
endfunction
function bit packet_transaction::compare(packet_transaction pkt2cmp, ref string message);
if(header != pkt2cmp.header) begin
message = "Header Mismatch:\n";
message = { message, $psprintf("Header Sent: %p\nHeader Received: %p", header, pkt2cmp.header) };
return(0);
end
if (payload.size() != pkt2cmp.payload.size()) begin
message = "Payload Size Mismatch:\n";
message = { message, $psprintf("payload.size() = %0d, pkt2cmp.payload.size() = %0d\n", payload.size(), pkt2cmp.payload.size()) };
return(0);
end
if (payload == pkt2cmp.payload) ;
else begin
message = "Payload Content Mismatch:\n";
message = { message, $psprintf("Packet Sent: %p\nPkt Received: %p", payload, pkt2cmp.payload) };
return(0);
end
message = "Successfully Compared";
return(1);
endfunction
function void packet_transaction::display(string prefix);
$display("[%s]%t %s", prefix, $realtime, name);
$display(" [%s]%t %s frame_interval = %0d", prefix, $realtime, name, frame_interval);
$display(" [%s]%t %s header = %0h", prefix, $realtime, name, header);
foreach(payload[i])
$display(" [%s]%t %s payload[%0d] = %0h", prefix, $realtime, name, i, payload[i]);
endfunction
function void packet_transaction::byte2pkt(ref logic[7:0] data[$]);
if(data.size() >= 2) begin
header[15:8] = data.pop_front();
header[7:0] = data.pop_front();
end
foreach(data[i]) begin
payload.push_back(data[i]);
end
endfunction
function packet_transaction packet_transaction::copy();
packet_transaction pkt_tran = new();
pkt_tran.frame_interval = this.frame_interval;
pkt_tran.header = this.header;
foreach(this.payload[i]) begin
pkt_tran.payload.push_back(this.payload[i]);
end
return pkt_tran;
endfunction
`endif
`define __PACKET_TRANSACTION_SV__
class packet_transaction;
string name;
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[$] ;
rand logic [6:0 ] frame_interval;
extern function new(string name = "Packet Transaction");
extern function void display(string prefix = "Note");
extern function bit compare(packet_transaction pkt2cmp, ref string message);
extern function void byte2pkt(ref logic[7:0] data[$]);
extern function packet_transaction copy();
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]});
}
constraint con_frame_interval {
frame_interval inside {[96:200]};
}
endclass
function packet_transaction::new(string name);
this.name = name;
endfunction
function bit packet_transaction::compare(packet_transaction pkt2cmp, ref string message);
if(header != pkt2cmp.header) begin
message = "Header Mismatch:\n";
message = { message, $psprintf("Header Sent: %p\nHeader Received: %p", header, pkt2cmp.header) };
return(0);
end
if (payload.size() != pkt2cmp.payload.size()) begin
message = "Payload Size Mismatch:\n";
message = { message, $psprintf("payload.size() = %0d, pkt2cmp.payload.size() = %0d\n", payload.size(), pkt2cmp.payload.size()) };
return(0);
end
if (payload == pkt2cmp.payload) ;
else begin
message = "Payload Content Mismatch:\n";
message = { message, $psprintf("Packet Sent: %p\nPkt Received: %p", payload, pkt2cmp.payload) };
return(0);
end
message = "Successfully Compared";
return(1);
endfunction
function void packet_transaction::display(string prefix);
$display("[%s]%t %s", prefix, $realtime, name);
$display(" [%s]%t %s frame_interval = %0d", prefix, $realtime, name, frame_interval);
$display(" [%s]%t %s header = %0h", prefix, $realtime, name, header);
foreach(payload[i])
$display(" [%s]%t %s payload[%0d] = %0h", prefix, $realtime, name, i, payload[i]);
endfunction
function void packet_transaction::byte2pkt(ref logic[7:0] data[$]);
if(data.size() >= 2) begin
header[15:8] = data.pop_front();
header[7:0] = data.pop_front();
end
foreach(data[i]) begin
payload.push_back(data[i]);
end
endfunction
function packet_transaction packet_transaction::copy();
packet_transaction pkt_tran = new();
pkt_tran.frame_interval = this.frame_interval;
pkt_tran.header = this.header;
foreach(this.payload[i]) begin
pkt_tran.payload.push_back(this.payload[i]);
end
return pkt_tran;
endfunction
`endif
//////////////////////////////////////////////////
// ./env/packet_env/packet_define.sv
//////////////////////////////////////////////////
`ifndef __PACKET_DEFINE_SV__
`define __PACKET_DEFINE_SV__
typedef class packet_transaction;
typedef mailbox #(packet_transaction) packet_tran_mbox;
`endif
`define __PACKET_DEFINE_SV__
typedef class packet_transaction;
typedef mailbox #(packet_transaction) packet_tran_mbox;
`endif
//////////////////////////////////////////////////
// ./env/packet_env/packet_generator.sv
//////////////////////////////////////////////////
`ifndef __PACKET_GENERATOR_SV__
`define __PACKET_GENERATOR_SV__
`include "packet_transaction.sv"
`include "packet_define.sv"
class packet_generator;
string name;
packet_tran_mbox drv_mbox;
int run_for_n_trans = 0;
packet_transaction pkt_tran = new();
event done;
extern function new(string name = "CPU Generator", packet_tran_mbox drv_mbox);
extern task start();
endclass
function packet_generator::new(string name, packet_tran_mbox drv_mbox);
this.name = name;
this.drv_mbox = drv_mbox;
endfunction
task packet_generator::start();
fork
begin
for(int i=0; i
packet_transaction pkt_tran_cpy = new pkt_tran;
if(!pkt_tran_cpy.randomize()) begin
$display("Error to randomize pkt_tran_cpy");
end
drv_mbox.put(pkt_tran_cpy);
end
->done;
end
join_none
endtask
`endif
`define __PACKET_GENERATOR_SV__
`include "packet_transaction.sv"
`include "packet_define.sv"
class packet_generator;
string name;
packet_tran_mbox drv_mbox;
int run_for_n_trans = 0;
packet_transaction pkt_tran = new();
event done;
extern function new(string name = "CPU Generator", packet_tran_mbox drv_mbox);
extern task start();
endclass
function packet_generator::new(string name, packet_tran_mbox drv_mbox);
this.name = name;
this.drv_mbox = drv_mbox;
endfunction
task packet_generator::start();
fork
begin
for(int i=0; i
if(!pkt_tran_cpy.randomize()) begin
$display("Error to randomize pkt_tran_cpy");
end
drv_mbox.put(pkt_tran_cpy);
end
->done;
end
join_none
endtask
`endif
//////////////////////////////////////////////////
// ./env/packet_env/packet_driver.sv
//////////////////////////////////////////////////
`ifndef __PACKET_DRIVER_SV__
`define __PACKET_DRIVER_SV__
`include "packet_transaction.sv"
`include "packet_define.sv"
`include "packet_interface.svi"
`include "transactor_callback.sv"
`include "transactor.sv"
class packet_driver extends transactor;
string name;
packet_tran_mbox gen2drv_mbox;
virtual packet_interface.master pkt_intf;
extern function new(string name = "CPU Driver", packet_tran_mbox gen2drv_mbox, virtual packet_interface.master pkt_intf);
extern task start();
endclass
class packet_driver_callback extends transactor_callback;
virtual task driver_pre_transactor (packet_driver xactor, ref packet_transaction pkt_tr, ref bit drop);
endtask
virtual task driver_post_transactor (packet_driver xactor, ref packet_transaction pkt_tr);
endtask
endclass
function packet_driver::new(string name, packet_tran_mbox gen2drv_mbox, virtual packet_interface.master pkt_intf);
super.new();
this.name = name;
this.gen2drv_mbox = gen2drv_mbox;
this.pkt_intf = pkt_intf;
endfunction
task packet_driver::start();
integer delay = 0;
bit drop = 0;
fork
forever begin
packet_transaction pkt_tran;
packet_transaction cb_pkt_tr;
gen2drv_mbox.get(pkt_tran);
//pkt_tran.display();
cb_pkt_tr = pkt_tran.copy();
`callback_macro(packet_driver_callback, driver_pre_transactor(this, cb_pkt_tr, drop))
@(pkt_intf.cb);
pkt_intf.cb.tx_vld <= 1'b1;
pkt_intf.cb.txd <= pkt_tran.header[15:8];
@(pkt_intf.cb);
pkt_intf.cb.txd <= pkt_tran.header[7:0];
foreach(pkt_tran.payload[i]) begin
@(pkt_intf.cb);
pkt_intf.cb.txd <= pkt_tran.payload[i];
end
if(pkt_tran.frame_interval > pkt_tran.payload.size())
delay = pkt_tran.frame_interval;
else
delay = pkt_tran.payload.size();
repeat(delay) begin
@(pkt_intf.cb);
pkt_intf.cb.tx_vld <= 1'b0;
end
end
join_none
endtask
`endif
`define __PACKET_DRIVER_SV__
`include "packet_transaction.sv"
`include "packet_define.sv"
`include "packet_interface.svi"
`include "transactor_callback.sv"
`include "transactor.sv"
class packet_driver extends transactor;
string name;
packet_tran_mbox gen2drv_mbox;
virtual packet_interface.master pkt_intf;
extern function new(string name = "CPU Driver", packet_tran_mbox gen2drv_mbox, virtual packet_interface.master pkt_intf);
extern task start();
endclass
class packet_driver_callback extends transactor_callback;
virtual task driver_pre_transactor (packet_driver xactor, ref packet_transaction pkt_tr, ref bit drop);
endtask
virtual task driver_post_transactor (packet_driver xactor, ref packet_transaction pkt_tr);
endtask
endclass
function packet_driver::new(string name, packet_tran_mbox gen2drv_mbox, virtual packet_interface.master pkt_intf);
super.new();
this.name = name;
this.gen2drv_mbox = gen2drv_mbox;
this.pkt_intf = pkt_intf;
endfunction
task packet_driver::start();
integer delay = 0;
bit drop = 0;
fork
forever begin
packet_transaction pkt_tran;
packet_transaction cb_pkt_tr;
gen2drv_mbox.get(pkt_tran);
//pkt_tran.display();
cb_pkt_tr = pkt_tran.copy();
`callback_macro(packet_driver_callback, driver_pre_transactor(this, cb_pkt_tr, drop))
@(pkt_intf.cb);
pkt_intf.cb.tx_vld <= 1'b1;
pkt_intf.cb.txd <= pkt_tran.header[15:8];
@(pkt_intf.cb);
pkt_intf.cb.txd <= pkt_tran.header[7:0];
foreach(pkt_tran.payload[i]) begin
@(pkt_intf.cb);
pkt_intf.cb.txd <= pkt_tran.payload[i];
end
if(pkt_tran.frame_interval > pkt_tran.payload.size())
delay = pkt_tran.frame_interval;
else
delay = pkt_tran.payload.size();
repeat(delay) begin
@(pkt_intf.cb);
pkt_intf.cb.tx_vld <= 1'b0;
end
end
join_none
endtask
`endif
//////////////////////////////////////////////////
// ./env/packet_env/packet_monitor.sv
//////////////////////////////////////////////////
`ifndef __PACKET_MONITOR_SV__
`define __PACKET_MONITOR_SV__
`include "packet_transaction.sv"
`include "packet_define.sv"
`include "packet_interface.svi"
`include "transactor_callback.sv"
`include "transactor.sv"
class packet_monitor extends transactor;
string name;
virtual packet_interface.master pkt_intf;
extern function new(string name = "CPU monitor", virtual packet_interface.master pkt_intf);
extern task start();
endclass
class packet_monitor_callback extends transactor_callback;
virtual task monitor_pre_transactor (packet_monitor xactor, ref packet_transaction pkt_tr, ref bit drop);
endtask
virtual task monitor_post_transactor (packet_monitor xactor, ref packet_transaction pkt_tr);
endtask
endclass
function packet_monitor::new(string name, virtual packet_interface.master pkt_intf);
super.new();
this.name = name;
this.pkt_intf = pkt_intf;
endfunction
task packet_monitor::start();
fork
forever begin
logic [7:0] rxd[$];
packet_transaction pkt_tran = new();
@(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
pkt_tran.byte2pkt(rxd);
//pkt_tran.display("Monitor");
`callback_macro(packet_monitor_callback, monitor_post_transactor(this, pkt_tran))
end
join_none
endtask
`endif
`define __PACKET_MONITOR_SV__
`include "packet_transaction.sv"
`include "packet_define.sv"
`include "packet_interface.svi"
`include "transactor_callback.sv"
`include "transactor.sv"
class packet_monitor extends transactor;
string name;
virtual packet_interface.master pkt_intf;
extern function new(string name = "CPU monitor", virtual packet_interface.master pkt_intf);
extern task start();
endclass
class packet_monitor_callback extends transactor_callback;
virtual task monitor_pre_transactor (packet_monitor xactor, ref packet_transaction pkt_tr, ref bit drop);
endtask
virtual task monitor_post_transactor (packet_monitor xactor, ref packet_transaction pkt_tr);
endtask
endclass
function packet_monitor::new(string name, virtual packet_interface.master pkt_intf);
super.new();
this.name = name;
this.pkt_intf = pkt_intf;
endfunction
task packet_monitor::start();
fork
forever begin
logic [7:0] rxd[$];
packet_transaction pkt_tran = new();
@(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
pkt_tran.byte2pkt(rxd);
//pkt_tran.display("Monitor");
`callback_macro(packet_monitor_callback, monitor_post_transactor(this, pkt_tran))
end
join_none
endtask
`endif
//////////////////////////////////////////////////
// ./env/packet_env/packet_rm.sv
//////////////////////////////////////////////////
`ifndef __PACKET_RM_SV__
`define __PACKET_RM_SV__
`include "packet_transaction.sv"
class packet_rm;
string name;
logic [9:0] min_pkt_size;
logic [9:0] max_pkt_size;
extern function new(string name="Packet RM", int unsigned min_pkt_size = 0, int unsigned max_pkt_size = 0);
extern function bit packet_process(ref packet_transaction pkt_tr);
endclass
function packet_rm::new(string name="Packet RM", int unsigned min_pkt_size = 0, int unsigned max_pkt_size = 0);
if(min_pkt_size == 0) begin
this.min_pkt_size = 32'd64;
end
else begin
this.min_pkt_size = min_pkt_size[9:0];
end
if(max_pkt_size == 0) begin
this.max_pkt_size = 32'd512;
end
else begin
this.max_pkt_size = max_pkt_size[9:0];
end
endfunction
function bit packet_rm::packet_process(ref packet_transaction pkt_tr);
if(pkt_tr == null) begin
return 0;
end
if(pkt_tr.header != 16'h55d5) begin
return 0;
end
if(pkt_tr.payload.size() < min_pkt_size - 2 || pkt_tr.payload.size() > max_pkt_size - 2) begin
return 0;
end
return 1;
endfunction
`endif
`define __PACKET_RM_SV__
`include "packet_transaction.sv"
class packet_rm;
string name;
logic [9:0] min_pkt_size;
logic [9:0] max_pkt_size;
extern function new(string name="Packet RM", int unsigned min_pkt_size = 0, int unsigned max_pkt_size = 0);
extern function bit packet_process(ref packet_transaction pkt_tr);
endclass
function packet_rm::new(string name="Packet RM", int unsigned min_pkt_size = 0, int unsigned max_pkt_size = 0);
if(min_pkt_size == 0) begin
this.min_pkt_size = 32'd64;
end
else begin
this.min_pkt_size = min_pkt_size[9:0];
end
if(max_pkt_size == 0) begin
this.max_pkt_size = 32'd512;
end
else begin
this.max_pkt_size = max_pkt_size[9:0];
end
endfunction
function bit packet_rm::packet_process(ref packet_transaction pkt_tr);
if(pkt_tr == null) begin
return 0;
end
if(pkt_tr.header != 16'h55d5) begin
return 0;
end
if(pkt_tr.payload.size() < min_pkt_size - 2 || pkt_tr.payload.size() > max_pkt_size - 2) begin
return 0;
end
return 1;
endfunction
`endif
//////////////////////////////////////////////////
// ./env/packet_env/packet_scoreboard.sv
//////////////////////////////////////////////////
`ifndef __PACKET_SCOREBOARD_SV__
`define __PACKET_SCOREBOARD_SV__
`include "packet_transaction.sv"
`include "packet_define.sv"
`include "packet_driver.sv"
`include "packet_monitor.sv"
`include "packet_rm.sv"
class packet_scoreboard;
string name;
packet_transaction ref_pkt_tran[$];
integer error_no = 0;
integer send_no = 0;
integer receive_no = 0;
logic [9:0] min_pkt_size;
logic [9:0] max_pkt_size;
extern function new(string name = "CPU Scoreboard");
extern function display(string prefix = "Packet Scoreboard Result");
endclass
function packet_scoreboard::new(string name);
this.name = name;
endfunction
class packet_driver_sb_callback extends packet_driver_callback;
packet_scoreboard pkt_sb;
packet_rm pkt_rm;
function new(packet_scoreboard pkt_sb, packet_rm pkt_rm);
this.pkt_sb = pkt_sb;
this.pkt_rm = pkt_rm;
endfunction
virtual task driver_pre_transactor (packet_driver xactor, ref packet_transaction pkt_tr, ref bit drop);
if(!pkt_rm.packet_process(pkt_tr)) begin
drop = 1;
end
else begin
pkt_sb.ref_pkt_tran.push_back(pkt_tr);
pkt_sb.send_no++;
drop = 0;
pkt_sb.display("[PKT][SEND]");
end
endtask
endclass
class packet_monitor_sb_callback extends packet_monitor_callback;
packet_scoreboard pkt_sb;
function new(packet_scoreboard pkt_sb);
this.pkt_sb = pkt_sb;
endfunction
virtual task monitor_post_transactor (packet_monitor xactor, ref packet_transaction pkt_tr);
pkt_sb.receive_no++;
if(pkt_sb.ref_pkt_tran.size() > 0) begin
packet_transaction ref_pkt_tr = pkt_sb.ref_pkt_tran.pop_front();
string message = "Scoreboare Comparison:\n";
if(!pkt_tr.compare(ref_pkt_tr, message)) begin
pkt_sb.error_no++;
end
message = { message, $psprintf("\n[PKT][RECV]") };
pkt_sb.display(message);
end
else begin
pkt_sb.error_no++;
pkt_sb.display("[PKT][RECV][RECV PKT > SEND PKT]");
pkt_tr.display("[PKT][RECV][Error]");
end
endtask
endclass
function packet_scoreboard::display(string prefix);
$display("%s Send: %d, Receive: %d, Error: %d", prefix, send_no, receive_no, error_no);
endfunction
`endif
`define __PACKET_SCOREBOARD_SV__
`include "packet_transaction.sv"
`include "packet_define.sv"
`include "packet_driver.sv"
`include "packet_monitor.sv"
`include "packet_rm.sv"
class packet_scoreboard;
string name;
packet_transaction ref_pkt_tran[$];
integer error_no = 0;
integer send_no = 0;
integer receive_no = 0;
logic [9:0] min_pkt_size;
logic [9:0] max_pkt_size;
extern function new(string name = "CPU Scoreboard");
extern function display(string prefix = "Packet Scoreboard Result");
endclass
function packet_scoreboard::new(string name);
this.name = name;
endfunction
class packet_driver_sb_callback extends packet_driver_callback;
packet_scoreboard pkt_sb;
packet_rm pkt_rm;
function new(packet_scoreboard pkt_sb, packet_rm pkt_rm);
this.pkt_sb = pkt_sb;
this.pkt_rm = pkt_rm;
endfunction
virtual task driver_pre_transactor (packet_driver xactor, ref packet_transaction pkt_tr, ref bit drop);
if(!pkt_rm.packet_process(pkt_tr)) begin
drop = 1;
end
else begin
pkt_sb.ref_pkt_tran.push_back(pkt_tr);
pkt_sb.send_no++;
drop = 0;
pkt_sb.display("[PKT][SEND]");
end
endtask
endclass
class packet_monitor_sb_callback extends packet_monitor_callback;
packet_scoreboard pkt_sb;
function new(packet_scoreboard pkt_sb);
this.pkt_sb = pkt_sb;
endfunction
virtual task monitor_post_transactor (packet_monitor xactor, ref packet_transaction pkt_tr);
pkt_sb.receive_no++;
if(pkt_sb.ref_pkt_tran.size() > 0) begin
packet_transaction ref_pkt_tr = pkt_sb.ref_pkt_tran.pop_front();
string message = "Scoreboare Comparison:\n";
if(!pkt_tr.compare(ref_pkt_tr, message)) begin
pkt_sb.error_no++;
end
message = { message, $psprintf("\n[PKT][RECV]") };
pkt_sb.display(message);
end
else begin
pkt_sb.error_no++;
pkt_sb.display("[PKT][RECV][RECV PKT > SEND PKT]");
pkt_tr.display("[PKT][RECV][Error]");
end
endtask
endclass
function packet_scoreboard::display(string prefix);
$display("%s Send: %d, Receive: %d, Error: %d", prefix, send_no, receive_no, error_no);
endfunction
`endif
//////////////////////////////////////////////////
// ./env/packet_env/packet_env.sv
//////////////////////////////////////////////////
`ifndef __PACKET_ENV_SV__
`define __PACKET_ENV_SV__
`include "packet_interface.svi"
`include "packet_transaction.sv"
`include "packet_generator.sv"
`include "packet_define.sv"
`include "packet_driver.sv"
`include "packet_scoreboard.sv"
`include "packet_monitor.sv"
`include "packet_rm.sv"
class packet_env;
packet_tran_mbox gen2drv_mbox = new(1);
packet_generator pkt_gen;
packet_driver pkt_drv;
packet_scoreboard pkt_sb;
packet_monitor pkt_mon;
packet_driver_sb_callback pkt_drv_sb_cb;
packet_monitor_sb_callback pkt_mon_sb_cb;
packet_rm pkt_rm;
virtual packet_interface.master pkt_intf;
extern function new(virtual packet_interface.master pkt_intf);
extern function configure();
extern task reset();
extern task start();
extern function report();
endclass
function packet_env::new(virtual packet_interface.master pkt_intf);
this.pkt_intf = pkt_intf;
pkt_gen = new("Packet Generator", gen2drv_mbox);
pkt_drv = new("Packet Driver", gen2drv_mbox, pkt_intf);
pkt_mon = new("Packet Monitor", pkt_intf);
pkt_sb = new("Packet Scoreboard");
pkt_rm = new("Packet RM");
pkt_drv_sb_cb = new(pkt_sb, pkt_rm);
pkt_mon_sb_cb = new(pkt_sb);
pkt_drv.append_callback(pkt_drv_sb_cb);
pkt_mon.append_callback(pkt_mon_sb_cb);
endfunction
function packet_env::configure();
endfunction
task packet_env::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
task packet_env::start();
pkt_gen.start();
pkt_drv.start();
pkt_mon.start();
endtask
function packet_env::report();
pkt_sb.display();
endfunction
`endif
`define __PACKET_ENV_SV__
`include "packet_interface.svi"
`include "packet_transaction.sv"
`include "packet_generator.sv"
`include "packet_define.sv"
`include "packet_driver.sv"
`include "packet_scoreboard.sv"
`include "packet_monitor.sv"
`include "packet_rm.sv"
class packet_env;
packet_tran_mbox gen2drv_mbox = new(1);
packet_generator pkt_gen;
packet_driver pkt_drv;
packet_scoreboard pkt_sb;
packet_monitor pkt_mon;
packet_driver_sb_callback pkt_drv_sb_cb;
packet_monitor_sb_callback pkt_mon_sb_cb;
packet_rm pkt_rm;
virtual packet_interface.master pkt_intf;
extern function new(virtual packet_interface.master pkt_intf);
extern function configure();
extern task reset();
extern task start();
extern function report();
endclass
function packet_env::new(virtual packet_interface.master pkt_intf);
this.pkt_intf = pkt_intf;
pkt_gen = new("Packet Generator", gen2drv_mbox);
pkt_drv = new("Packet Driver", gen2drv_mbox, pkt_intf);
pkt_mon = new("Packet Monitor", pkt_intf);
pkt_sb = new("Packet Scoreboard");
pkt_rm = new("Packet RM");
pkt_drv_sb_cb = new(pkt_sb, pkt_rm);
pkt_mon_sb_cb = new(pkt_sb);
pkt_drv.append_callback(pkt_drv_sb_cb);
pkt_mon.append_callback(pkt_mon_sb_cb);
endfunction
function packet_env::configure();
endfunction
task packet_env::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
task packet_env::start();
pkt_gen.start();
pkt_drv.start();
pkt_mon.start();
endtask
function packet_env::report();
pkt_sb.display();
endfunction
`endif
//////////////////////////////////////////////////
// ./env/env.sv
//////////////////////////////////////////////////
`ifndef __ENV_SV__
`define __ENV_SV__
`include "cpu_interface.svi"
`include "packet_interface.svi"
`include "cpu_env.sv"
`include "packet_env.sv"
class env;
cpu_env cpu_e;
packet_env pkt_e;
extern function new(virtual cpu_interface.master cpu_intf, virtual packet_interface.master pkt_intf);
extern function configure();
extern task reset();
extern task start();
extern function report();
endclass
function env::new(virtual cpu_interface.master cpu_intf, virtual packet_interface.master pkt_intf);
cpu_e = new(cpu_intf);
pkt_e = new(pkt_intf);
endfunction
function env::configure();
cpu_e.configure();
pkt_e.configure();
endfunction
task env::reset();
cpu_e.reset();
pkt_e.reset();
endtask
task env::start();
cpu_e.start();
pkt_e.start();
endtask
function env::report();
cpu_e.report();
pkt_e.report();
endfunction
`endif
`define __ENV_SV__
`include "cpu_interface.svi"
`include "packet_interface.svi"
`include "cpu_env.sv"
`include "packet_env.sv"
class env;
cpu_env cpu_e;
packet_env pkt_e;
extern function new(virtual cpu_interface.master cpu_intf, virtual packet_interface.master pkt_intf);
extern function configure();
extern task reset();
extern task start();
extern function report();
endclass
function env::new(virtual cpu_interface.master cpu_intf, virtual packet_interface.master pkt_intf);
cpu_e = new(cpu_intf);
pkt_e = new(pkt_intf);
endfunction
function env::configure();
cpu_e.configure();
pkt_e.configure();
endfunction
task env::reset();
cpu_e.reset();
pkt_e.reset();
endtask
task env::start();
cpu_e.start();
pkt_e.start();
endtask
function env::report();
cpu_e.report();
pkt_e.report();
endfunction
`endif
//////////////////////////////////////////////////
// ./test/test.sv
//////////////////////////////////////////////////
`ifndef __TEST_SV__
`define __TEST_SV__
`include "env.sv"
program test(cpu_interface.master cpu_intf, packet_interface.master pkt_intf);
class packet_transaction_ext extends packet_transaction;
//constraint con_pkt_len_test {
// payload.size() == 100;
// pkt_head_type == GOOD;
//}
endclass
cpu_transaction cpu_tran;
cpu_transaction cpu_tran_cpy;
packet_transaction_ext pkt_tran;
env e;
initial begin
cpu_tran = new();
pkt_tran = new();
e = new(cpu_intf, pkt_intf);
e.configure();
e.pkt_e.pkt_gen.pkt_tran = pkt_tran;
e.reset();
e.start();
cpu_tran.randomize() with {addr == 'h4; rw == 1'b0; dout == 'd65;};
cpu_tran_cpy = cpu_tran.copy();
e.cpu_e.drv_mbox.put(cpu_tran_cpy);
cpu_tran.randomize() with {addr == 'h8; rw == 1'b0; dout == 'd500;};
cpu_tran_cpy = cpu_tran.copy();
e.cpu_e.drv_mbox.put(cpu_tran_cpy);
cpu_tran.randomize() with {addr == 'h0; rw == 1'b0; dout == 'h1;};
cpu_tran_cpy = cpu_tran.copy();
e.cpu_e.drv_mbox.put(cpu_tran_cpy);
repeat(100) begin
@(cpu_intf.cb);
end
e.pkt_e.pkt_sb.min_pkt_size = 65;
e.pkt_e.pkt_sb.max_pkt_size = 500;
e.pkt_e.pkt_rm.min_pkt_size = 65;
e.pkt_e.pkt_rm.max_pkt_size = 500;
e.pkt_e.pkt_gen.run_for_n_trans = 100;
e.pkt_e.pkt_gen.start();
@e.pkt_e.pkt_gen.done;
repeat(10000) begin
@(pkt_intf.cb);
if(e.pkt_e.pkt_sb.send_no == e.pkt_e.pkt_gen.run_for_n_trans) begin
break;
end
end
e.report();
$finish();
end
endprogram
`endif
`define __TEST_SV__
`include "env.sv"
program test(cpu_interface.master cpu_intf, packet_interface.master pkt_intf);
class packet_transaction_ext extends packet_transaction;
//constraint con_pkt_len_test {
// payload.size() == 100;
// pkt_head_type == GOOD;
//}
endclass
cpu_transaction cpu_tran;
cpu_transaction cpu_tran_cpy;
packet_transaction_ext pkt_tran;
env e;
initial begin
cpu_tran = new();
pkt_tran = new();
e = new(cpu_intf, pkt_intf);
e.configure();
e.pkt_e.pkt_gen.pkt_tran = pkt_tran;
e.reset();
e.start();
cpu_tran.randomize() with {addr == 'h4; rw == 1'b0; dout == 'd65;};
cpu_tran_cpy = cpu_tran.copy();
e.cpu_e.drv_mbox.put(cpu_tran_cpy);
cpu_tran.randomize() with {addr == 'h8; rw == 1'b0; dout == 'd500;};
cpu_tran_cpy = cpu_tran.copy();
e.cpu_e.drv_mbox.put(cpu_tran_cpy);
cpu_tran.randomize() with {addr == 'h0; rw == 1'b0; dout == 'h1;};
cpu_tran_cpy = cpu_tran.copy();
e.cpu_e.drv_mbox.put(cpu_tran_cpy);
repeat(100) begin
@(cpu_intf.cb);
end
e.pkt_e.pkt_sb.min_pkt_size = 65;
e.pkt_e.pkt_sb.max_pkt_size = 500;
e.pkt_e.pkt_rm.min_pkt_size = 65;
e.pkt_e.pkt_rm.max_pkt_size = 500;
e.pkt_e.pkt_gen.run_for_n_trans = 100;
e.pkt_e.pkt_gen.start();
@e.pkt_e.pkt_gen.done;
repeat(10000) begin
@(pkt_intf.cb);
if(e.pkt_e.pkt_sb.send_no == e.pkt_e.pkt_gen.run_for_n_trans) begin
break;
end
end
e.report();
$finish();
end
endprogram
`endif
//////////////////////////////////////////////////
// ./env/top.sv
//////////////////////////////////////////////////
`timescale 1ns/1ps
`include "cpu_interface.svi"
`include "packet_interface.svi"
`include "test.sv"
module top;
parameter clock_cycle = 10;
logic clk;
cpu_interface cpu_intf(clk);
packet_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 "packet_interface.svi"
`include "test.sv"
module top;
parameter clock_cycle = 10;
logic clk;
cpu_interface cpu_intf(clk);
packet_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/svtb
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)
SVTB = $(TB_DIR)/env.sv $(TB_DIR)/top.sv
TEST_DIR = $(PROJECT_DIR)/test
TEST_FILE = $(TEST_DIR)/test.sv
INCDIR += +incdir+$(TEST_DIR)
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)
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) $(SVTB) $(TEST_FILE)
clean:
rm -rf simv simv.* *log