//dut.v
/////////////////////////////////////////////
`timescale 1ns/1ps
module dut(
clk ,
rst_n ,
txd ,
tx_vld ,
rxd ,
rx_vld
);
input clk ;
input rst_n ;
input [7:0] rxd ;
input rx_vld ;
output [7:0] txd ;
output tx_vld ;
wire clk ;
wire rst_n ;
wire [7:0] rxd ;
wire rx_vld ;
reg [7:0] txd ;
reg tx_vld ;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
txd <= 8'h0;
tx_vld <= 1'b0;
end
else begin
txd <= rxd;
tx_vld <= rx_vld;
end
end
endmodule
/////////////////////////////////////////////
//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
/////////////////////////////////////////////
//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[$] ;
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]});
}
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 header = %0h", prefix, $realtime, name, header);
foreach(payload[i])
$display(" [%s]%t %s payload[%0d] = %0d", 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.header = this.header;
foreach(this.payload[i]) begin
pkt_tran.payload.push_back(this.payload[i]);
end
return pkt_tran;
endfunction
`endif
/////////////////////////////////////////////
//packet_define.sv
/////////////////////////////////////////////
`ifndef __PACKET_DEFINE_SV__
`define __PACKET_DEFINE_SV__
typedef class packet_transaction;
typedef mailbox #(packet_transaction) packet_tran_mbox;
`endif
/////////////////////////////////////////////
//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;
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<run_for_n_trans; i++) begin
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
/////////////////////////////////////////////
//packet_driver.sv
/////////////////////////////////////////////
`ifndef __PACKET_DRIVER_SV__
`define __PACKET_DRIVER_SV__
`include "packet_transaction.sv"
`include "packet_define.sv"
`include "packet_interface.svi"
class packet_driver;
string name;
packet_tran_mbox gen2drv_mbox;
packet_tran_mbox drv2sb_mbox;
virtual packet_interface.master pkt_intf;
extern function new(string name = "CPU Driver", packet_tran_mbox gen2drv_mbox, packet_tran_mbox drv2sb_mbox, virtual packet_interface.master pkt_intf);
extern task start();
endclass
function packet_driver::new(string name, packet_tran_mbox gen2drv_mbox, packet_tran_mbox drv2sb_mbox, virtual packet_interface.master pkt_intf);
this.name = name;
this.gen2drv_mbox = gen2drv_mbox;
this.drv2sb_mbox = drv2sb_mbox;
this.pkt_intf = pkt_intf;
endfunction
task packet_driver::start();
fork
forever begin
packet_transaction pkt_tran;
gen2drv_mbox.get(pkt_tran);
//pkt_tran.display();
drv2sb_mbox.put(pkt_tran.copy());
@(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
@(pkt_intf.cb);
pkt_intf.cb.tx_vld <= 1'b0;
end
join_none
endtask
`endif
/////////////////////////////////////////////
//packet_monitor.sv
/////////////////////////////////////////////
`ifndef __PACKET_MONITOR_SV__
`define __PACKET_MONITOR_SV__
`include "packet_transaction.sv"
`include "packet_define.sv"
`include "packet_interface.svi"
class packet_monitor;
string name;
packet_tran_mbox out_box;
virtual packet_interface.master pkt_intf;
extern function new(string name = "CPU monitor", packet_tran_mbox out_box, virtual packet_interface.master pkt_intf);
extern task start();
endclass
function packet_monitor::new(string name, packet_tran_mbox out_box, virtual packet_interface.master pkt_intf);
this.name = name;
this.out_box = out_box;
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");
out_box.put(pkt_tran);
end
join_none
endtask
`endif
/////////////////////////////////////////////
//packet_scoreboard.sv
/////////////////////////////////////////////
`ifndef __PACKET_SCOREBOARD_SV__
`define __PACKET_SCOREBOARD_SV__
`include "packet_transaction.sv"
`include "packet_define.sv"
class packet_scoreboard;
string name;
packet_tran_mbox drv2sb_mbox;
packet_tran_mbox mon2sb_mbox;
packet_transaction ref_pkt_tran[$];
integer error_no = 0;
integer send_no = 0;
integer receive_no = 0;
extern function new(string name = "CPU Scoreboard", packet_tran_mbox drv2sb_mbox, packet_tran_mbox mon2sb_mbox);
extern task start();
extern task get_pkt_from_mon_and_check();
extern function display(string prefix = "Packet Scoreboard Result");
endclass
function packet_scoreboard::new(string name, packet_tran_mbox drv2sb_mbox, packet_tran_mbox mon2sb_mbox);
this.name = name;
this.drv2sb_mbox = drv2sb_mbox;
this.mon2sb_mbox = mon2sb_mbox;
endfunction
task packet_scoreboard::start();
fork
get_pkt_from_mon_and_check();
join_none
endtask
task packet_scoreboard::get_pkt_from_mon_and_check();
string message;
packet_transaction pkt_tran_mon;
packet_transaction pkt_tran_drv;
forever begin
message = "Scoreboare Comparison";
mon2sb_mbox.get(pkt_tran_mon);
receive_no++;
drv2sb_mbox.get(pkt_tran_drv);
send_no++;
if(!pkt_tran_drv.compare(pkt_tran_mon, message)) begin
error_no++;
end
$display(message);
end
endtask
function packet_scoreboard::display(string prefix);
$display("Send: %d, Receive: %d, Error: %d", send_no + drv2sb_mbox.num(), receive_no, error_no);
endfunction
`endif
/////////////////////////////////////////////
//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"
class packet_env;
packet_tran_mbox gen2drv_mbox = new(1);
packet_tran_mbox drv2sb_mbox = new();
packet_tran_mbox mon2sb_mbox = new();
packet_generator pkt_gen;
packet_driver pkt_drv;
packet_scoreboard pkt_sb;
packet_monitor pkt_mon;
virtual packet_interface.master pkt_intf;
extern function new(virtual packet_interface.master pkt_intf);
extern function configure();
extern task reset();
extern task start();
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, drv2sb_mbox, pkt_intf);
pkt_mon = new("Packet Monitor", mon2sb_mbox, pkt_intf);
pkt_sb = new("Packet Scoreboard", drv2sb_mbox, mon2sb_mbox);
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();
pkt_sb.start();
endtask
`endif
/////////////////////////////////////////////
//test.sv
/////////////////////////////////////////////
`ifndef __TEST_SV__
`define __TEST_SV__
`include "packet_interface.svi"
`include "packet_transaction.sv"
`include "packet_env.sv"
program test(packet_interface.master pkt_intf);
class packet_transaction_ext extends packet_transaction;
//constraint addr_range {addr[7:2] inside {[8'h0:8'h1]}; addr[1:0] == 2'h0;}
//constraint write {rw == 1'b0;}
endclass
packet_transaction_ext packet_tran_ext = new();
packet_env pkt_e;
initial begin
pkt_e = new(pkt_intf);
pkt_e.configure();
pkt_e.pkt_gen.pkt_tran = packet_tran_ext;
pkt_e.pkt_gen.run_for_n_trans = 100;
pkt_e.reset();
pkt_e.start();
@pkt_e.pkt_gen.done;
repeat(10000) begin
@(pkt_intf.cb);
if(pkt_e.pkt_sb.send_no == pkt_e.pkt_gen.run_for_n_trans) begin
break;
end
end
pkt_e.pkt_sb.display();
$finish();
end
endprogram
`endif
/////////////////////////////////////////////
//top.sv
/////////////////////////////////////////////
`timescale 1ns/1ps
`include "packet_interface.svi"
`include "test.sv"
module top;
parameter pkt_clock_cycle = 10;
logic clk;
packet_interface pkt_intf(clk);
test u_test(pkt_intf);
dut u_dut (
.clk (pkt_intf.clk ) ,
.rst_n (pkt_intf.rst_n ) ,
.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
#(pkt_clock_cycle/2) clk = ~clk;
end
end
`ifdef WAVE_ON
initial begin
$vcdpluson();
end
`endif
endmodule
#############################################
#Makefile
#############################################
ifeq ($(GUI), 1)
GUI_ARG = -gui
endif
RTL_DIR = /mnt/packet
RTL = $(RTL_DIR)/dut.v
TB_DIR = /mnt/packet
SVTB = $(TB_DIR)/top.sv
INCDIR = +incdir+$(TB_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) $(SVTB) $(RTL)
clean:
rm -rf simv simv.* *log
No comments:
Post a Comment