Wednesday, December 24, 2014

an example of UVM TB

./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     ,
    enable ,
    dout   ,

    txd    ,
    tx_vld ,
    rxd    ,
    rx_vld  
);

input         clk    ;
input         rst_n  ;

input  [7:0 ] addr   ;
input  [31:0] din    ;
input         rw     ;
input         enable ;
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     ;
wire        enable ;
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 && enable == 1'b1);
assign read  = (rw == 1'b1 && enable == 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/cpu_interface_env/cpu_interface.svi
`ifndef __CPU_INTERFACE_SVI__
`define __CPU_INTERFACE_SVI__
interface cpu_interface (input logic clk, input logic rst_n);

logic [7:0 ] addr   ;
logic [31:0] din    ;
logic        rw     ;
logic        enable ;
logic [31:0] dout   ;

clocking cb @(posedge clk);
    default input #1 output #1;
    output addr   ;
    output rw     ;
    output enable ;
    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 extends uvm_sequence_item;

typedef enum {READ, WRITE} rw_type;
rand logic [7:0] addr;
rand rw_type rw;
rand logic [31:0] dout;
logic [31:0] din = 32'h0;

extern function new(string name = "CPU Transaction");

`uvm_object_utils_begin(cpu_transaction)
    `uvm_field_int(addr, UVM_ALL_ON)
    `uvm_field_enum(rw_type, rw, UVM_ALL_ON)
    `uvm_field_int(dout, UVM_ALL_ON)
`uvm_object_utils_end

endclass

function cpu_transaction::new(string name = "CPU Transaction");
    super.new(name);
endfunction

`endif


./env/cpu_interface_env/cpu_sequencer.sv
`ifndef __CPU_SEQUENCER_SV__
`define __CPU_SEQUENCER_SV__

`include "cpu_transaction.sv"

class cpu_sequencer extends uvm_sequencer #(cpu_transaction);

`uvm_component_utils(cpu_sequencer)

function new(string name, uvm_component parent=null);
    super.new(name, parent);
endfunction

endclass

`endif


./env/cpu_interface_env/cpu_driver.sv
`ifndef __CPU_DRIVER_SV__
`define __CPU_DRIVER_SV__

`include "cpu_interface.svi"
`include "cpu_transaction.sv"

class cpu_driver extends uvm_driver #(cpu_transaction);

protected virtual cpu_interface cpu_vif;

`uvm_component_utils(cpu_driver)

extern function new(string name, uvm_component parent);
extern function void build_phase(uvm_phase phase);
extern task main_phase(uvm_phase phase);

task reset_phase(uvm_phase phase);
    super.reset_phase(phase);

    phase.raise_objection(this);

    cpu_vif.cb.addr   <= 'h0;
    cpu_vif.cb.dout   <= 'h0;
    cpu_vif.cb.rw     <= 1'b0;
    cpu_vif.cb.enable <= 1'b0;
    @(posedge cpu_vif.rst_n);
    repeat(10) @(cpu_vif.cb);

    phase.drop_objection(this);
endtask;
 
virtual protected task get_and_drive();
    forever begin
        cpu_transaction cpu_tr;
        seq_item_port.get_next_item(cpu_tr);
        //cpu_tr.print();

        @(cpu_vif.cb);
        cpu_vif.cb.addr   <= cpu_tr.addr;
        cpu_vif.cb.dout   <= cpu_tr.dout;
        if(cpu_tr.rw == cpu_transaction::WRITE) begin
            cpu_vif.cb.rw <= 1'b0;
        end
        else begin
            cpu_vif.cb.rw <= 1'b1;
        end
        cpu_vif.cb.enable <= 1'b1;

        @(cpu_vif.cb);
        cpu_vif.cb.enable <= 1'b0;

        //`uvm_do_callbacks(cpu_driver, cpu_driver_cbs, driver_post_transactor(this, cpu_tr))
        seq_item_port.item_done();
    end
endtask

endclass

//class cpu_driver_cbs extends uvm_callback;
//virtual task driver_pre_transactor(cpu_driver xactor, cpu_transaction cpu_tr); endtask
//virtual task driver_post_transactor(cpu_driver xactor, cpu_transaction cpu_tr); endtask
//endclass

function cpu_driver::new(string name, uvm_component parent);
    super.new(name, parent);
endfunction

function void cpu_driver::build_phase(uvm_phase phase);
    super.build_phase(phase);

    if(!uvm_config_db#(virtual cpu_interface)::get(this, "", "cpu_vif", cpu_vif)) begin
        `uvm_fatal("NOVIF", {"virutal interface must be set for: ", get_full_name(), ".cpu_vif"});
    end

endfunction

task cpu_driver::main_phase(uvm_phase phase);
    super.main_phase(phase);

    `uvm_info(get_full_name(),$sformatf(" CPU Driver"), UVM_MEDIUM)

    fork
      get_and_drive();
    join
endtask

`endif


./env/cpu_interface_env/cpu_monitor.sv
`ifndef __CPU_MONITOR_SV__
`define __CPU_MONITOR_SV__

`include "cpu_interface.svi"
`include "cpu_transaction.sv"

//typedef class cpu_monitor;

//class cpu_monitor_cbs extends uvm_callback;
//  virtual function void trans_observed(cpu_monitor xactor, cpu_transaction cycle);
//  endfunction
//endclass

class cpu_monitor extends uvm_monitor;

virtual cpu_interface cpu_vif;

bit checks_enable = 1;
bit coverage_enable = 1;

uvm_analysis_port #(cpu_transaction) item_collected_port;

`uvm_component_utils_begin(cpu_monitor)
  `uvm_field_int(checks_enable, UVM_DEFAULT)
  `uvm_field_int(coverage_enable, UVM_DEFAULT)
`uvm_component_utils_end

function new (string name, uvm_component parent);
    super.new(name, parent);
    item_collected_port = new("item_collected_port", this);
endfunction

function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if(!uvm_config_db#(virtual cpu_interface)::get(this, "", "cpu_vif", cpu_vif)) begin
        `uvm_fatal("NOVIF",{"virtual interface must be set for: ", get_full_name(), ".cpu_vif"});
    end

endfunction

virtual protected task collect_transactions();
    @(posedge cpu_vif.rst_n);

    forever begin
        cpu_transaction cpu_tr = new();

        do begin
            @(cpu_vif.cb);
        end while(cpu_vif.enable == 1'b0);

        cpu_tr.din  = cpu_vif.din;
        cpu_tr.addr = cpu_vif.addr;
        if(cpu_vif.rw == 1'b0) begin
            cpu_tr.rw   = cpu_transaction::WRITE;
        end
        else begin
            cpu_tr.rw   = cpu_transaction::READ;
        end
        cpu_tr.dout = cpu_vif.dout;

        //`uvm_do_callbacks(cpu_monitor, cpu_monitor_cbs, trans_observed(this,cpu_tr))
        item_collected_port.write(cpu_tr);
    end
endtask
 
virtual task main_phase(uvm_phase phase);
    super.main_phase(phase);
    `uvm_info(get_full_name(),$sformatf(" CPU Monitor"), UVM_MEDIUM)

    fork
        collect_transactions();
    join
endtask

virtual function void report_phase(uvm_phase phase);
    super.report_phase(phase);
endfunction

endclass

`endif


./env/cpu_interface_env/cpu_agent.sv
`ifndef __CPU_AGENT_SV__
`define __CPU_AGENT_SV__

`include "cpu_sequencer.sv"
`include "cpu_driver.sv"
`include "cpu_monitor.sv"

class cpu_agent extends uvm_agent;
cpu_sequencer  cpu_sqr;
cpu_driver     cpu_drv;
cpu_monitor    cpu_mon;

`uvm_component_utils_begin(cpu_agent)
    `uvm_field_object(cpu_sqr, UVM_ALL_ON)
    `uvm_field_object(cpu_drv, UVM_ALL_ON)
    `uvm_field_object(cpu_mon, UVM_ALL_ON)
`uvm_component_utils_end

function new(string name, uvm_component parent = null);
    super.new(name, parent);
endfunction

virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    cpu_sqr = cpu_sequencer::type_id::create("cpu_sqr", this);
    cpu_drv = cpu_driver::type_id::create("cpu_drv", this);
    cpu_mon = cpu_monitor::type_id::create("cpu_mon", this);

endfunction

virtual function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);

    cpu_drv.seq_item_port.connect(cpu_sqr.seq_item_export);
endfunction

endclass

`endif


./env/cpu_interface_env/cpu_scoreboard.sv
`ifndef __CPU_SCOREBOARD_SV__
`define __CPU_SCOREBOARD_SV__

`include "cpu_transaction.sv"

class cpu_scoreboard extends uvm_scoreboard;

uvm_analysis_imp#(cpu_transaction, cpu_scoreboard) item_collected_export;

protected bit disable_scoreboard = 0;
int sbd_error = 0;
logic [31:0] cpu_reg [7:0];
integer error_no = 0;
integer total_no = 0;

`uvm_component_utils_begin(cpu_scoreboard)
    `uvm_field_int(disable_scoreboard, UVM_DEFAULT)
`uvm_component_utils_end

function new(string name, uvm_component parent);
    super.new(name, parent);

    for(int i=0; i<128 data-blogger-escaped-begin="" data-blogger-escaped-br="" data-blogger-escaped-i="" data-blogger-escaped-nbsp="">         cpu_reg[i] = 32'h0;
    end
endfunction

function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    item_collected_export = new("item_collected_export", this);
endfunction
 
virtual function void write(cpu_transaction tr);
    if(!disable_scoreboard) begin
        compare(tr);
    end
endfunction : write

protected function void compare(cpu_transaction data);
    cpu_transaction tr;
    string message;

    $cast(tr, data);

    if(tr.rw == cpu_transaction::WRITE) begin
        cpu_reg[tr.addr] = tr.din;
    end
    else if(tr.rw == cpu_transaction::READ) 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 READ or WRITE");
        error_no++;
    end
endfunction

virtual function void report_phase(uvm_phase phase);
    super.report_phase(phase);

    $dipslay(phase.get_state());

    if(!disable_scoreboard) begin
        `uvm_info(get_type_name(), $sformatf("Reporting scoreboard information...\n%s", this.sprint()), UVM_LOW)
    end
endfunction

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

`endif


./env/cpu_interface_env/cpu_env.sv
`ifndef __CPU_ENV_SV__
`define __CPU_ENV_SV__

`include "cpu_agent.sv"
`include "cpu_scoreboard.sv"

class cpu_env extends uvm_env;

cpu_agent      cpu_agt;
cpu_scoreboard cpu_sb;


protected virtual interface cpu_interface cpu_vif;

//`uvm_component_utils_begin(cpu_env)
//    //`uvm_field_object(cpu_sb, UVM_ALL_ON)
//`uvm_component_utils_end
`uvm_component_utils(cpu_env)

function new(string name, uvm_component parent);
    super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    cpu_agt = cpu_agent::type_id::create("cpu_agt", this);
    cpu_sb = cpu_scoreboard::type_id::create("cpu_sb", this);

endfunction

function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    cpu_agt.cpu_mon.item_collected_port.connect(cpu_sb.item_collected_export);
endfunction : connect_phase

task run_phase(uvm_phase phase);
    super.run_phase(phase);
endtask

endclass

`endif


./env/packet_env/packet_interface.svi
`ifndef __PACKET_INTERFACE_SVI__
`define __PACKET_INTERFACE_SVI__
interface packet_interface (input logic clk, input 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 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 extends uvm_sequence_item;

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");

function void 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

`uvm_object_utils_begin(packet_transaction)
    `uvm_field_enum(head_type, pkt_head_type, UVM_ALL_ON | UVM_NOCOMPARE)
    `uvm_field_enum(packet_length, pkt_packet_length, UVM_ALL_ON | UVM_NOCOMPARE)
    `uvm_field_int(header, UVM_ALL_ON)
    `uvm_field_queue_int(payload, UVM_ALL_ON)
    `uvm_field_int(frame_interval, UVM_ALL_ON | UVM_NOCOMPARE)
`uvm_object_utils_end

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]};
}

virtual function bit do_compare (uvm_object rhs, uvm_comparer comparer);
      packet_transaction rhs_;
      do_compare = super.do_compare(rhs,comparer);

      $cast(rhs_,rhs);
      do_compare &= comparer.compare_field_int("Header", header, rhs_.header, 16);
      do_compare &= comparer.compare_field_int("Payload Size", payload.size(), rhs_.payload.size(), 64);
      if(do_compare) begin
          foreach (rhs_.payload[i]) begin
              do_compare &= comparer.compare_field_int("Payload", payload[i], rhs_.payload[i], 8);
          end
      end

endfunction

function uvm_object clone();
    packet_transaction tr = new();

    tr.copy(this);
    return tr;
endfunction

function void do_copy (uvm_object rhs);
    packet_transaction rhs_;
    super.do_copy(rhs);

    $cast(rhs_, rhs);

    header = rhs_.header;
    foreach(rhs_.payload[i]) begin
        payload.push_back(rhs_.payload[i]);
    end

endfunction

endclass

function packet_transaction::new(string name = "Packet Transaction");
    super.new(name);
endfunction

`endif


./env/packet_env/packet_sequencer.sv
`ifndef __PACKET_SEQUENCER_SV__
`define __PACKET_SEQUENCER_SV__

`include "packet_transaction.sv"

class packet_sequencer extends uvm_sequencer #(packet_transaction);

`uvm_component_utils(packet_sequencer)

function new(string name, uvm_component parent=null);
    super.new(name, parent);
endfunction

endclass

`endif


./env/packet_env/packet_driver.sv
`ifndef __PACKET_DRIVER_SV__
`define __PACKET_DRIVER_SV__

`include "packet_interface.svi"
`include "packet_transaction.sv"

class packet_driver extends uvm_driver #(packet_transaction);

virtual packet_interface pkt_vif;
uvm_analysis_port #(packet_transaction) drv2sb_port;

`uvm_component_utils(packet_driver)

extern function new(string name, uvm_component parent);
extern function void build_phase(uvm_phase phase);
extern task main_phase(uvm_phase phase);

task reset_phase(uvm_phase phase);
    super.reset_phase(phase);

    phase.raise_objection(this);

    pkt_vif.cb.tx_vld <= 1'b0;
    pkt_vif.cb.txd    <= 8'h0;
    @(posedge pkt_vif.rst_n);
    repeat(10) @(pkt_vif.cb);

    phase.drop_objection(this);
endtask;


virtual protected task get_and_drive();

    forever begin
        int delay;
        packet_transaction pkt_tr;
        packet_transaction cb_pkt_tr;

        seq_item_port.get_next_item(pkt_tr);
        //pkt_tr.display();

        //cb_pkt_tr = pkt_tr.copy();
        //`callback_macro(packet_driver_callback, driver_pre_transactor(this, cb_pkt_tr, drop))
        drv2sb_port.write(pkt_tr);

        @(pkt_vif.cb);
        pkt_vif.cb.tx_vld <= 1'b1;
        pkt_vif.cb.txd    <= pkt_tr.header[15:8];
        @(pkt_vif.cb);
        pkt_vif.cb.txd    <= pkt_tr.header[7:0];

        foreach(pkt_tr.payload[i]) begin
            @(pkt_vif.cb);
            pkt_vif.cb.txd    <= pkt_tr.payload[i];
        end

        if(pkt_tr.frame_interval > pkt_tr.payload.size())
            delay = pkt_tr.frame_interval;
        else
            delay = pkt_tr.payload.size();
        repeat(delay) begin
            @(pkt_vif.cb);
            pkt_vif.cb.tx_vld <= 1'b0;
        end

        seq_item_port.item_done();

    end
endtask

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, uvm_component parent);
    super.new(name, parent);

    drv2sb_port = new("drv2sb_port", this);
endfunction

function void packet_driver::build_phase(uvm_phase phase);
    super.build_phase(phase);

    if(!uvm_config_db#(virtual packet_interface)::get(this, "", "pkt_vif", pkt_vif)) begin
        `uvm_fatal("NOVIF", {"virutal interface must be set for: ", get_full_name(), ".pkt_vif"});
    end
endfunction

task packet_driver::main_phase(uvm_phase phase);
    super.main_phase(phase);

    `uvm_info(get_full_name(),$sformatf(" Packet Driver"), UVM_MEDIUM)

    fork
        get_and_drive();
    join
endtask

`endif


./env/packet_env/packet_monitor.sv
`ifndef __PACKET_MONITOR_SV__
`define __PACKET_MONITOR_SV__

`include "packet_interface.svi"
`include "packet_transaction.sv"

class packet_monitor extends uvm_monitor;

virtual packet_interface pkt_vif;

bit checks_enable = 1;
bit coverage_enable = 1;

uvm_analysis_port #(packet_transaction) mon2sb_port;

`uvm_component_utils_begin(packet_monitor)
  `uvm_field_int(checks_enable, UVM_DEFAULT)
  `uvm_field_int(coverage_enable, UVM_DEFAULT)
`uvm_component_utils_end

function new (string name, uvm_component parent);
    super.new(name, parent);

    mon2sb_port = new("mon2sb_port", this);
endfunction

function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    if(!uvm_config_db#(virtual packet_interface)::get(this, "", "pkt_vif", pkt_vif))
        `uvm_fatal("NOVIF",{"virtual interface must be set for: ", get_full_name(), ".pkt_vif"});
endfunction

virtual task main_phase(uvm_phase phase);
    super.main_phase(phase);

    `uvm_info(get_full_name(),$sformatf(" Packet Monitor"), UVM_MEDIUM)

    fork
        collect_transactions();
    join
endtask

virtual protected task collect_transactions();
    //or wait for the global reset
    @(pkt_vif.cb);
    while(pkt_vif.cb.rx_vld !== 1'b0) begin
        @(pkt_vif.cb);
    end

    forever begin
        logic [7:0] rxd[$];
        packet_transaction pkt_tr = new();

        @(pkt_vif.cb);
        while(pkt_vif.cb.rx_vld == 1'b0) begin
            @(pkt_vif.cb);
        end

        while(pkt_vif.cb.rx_vld == 1'b1) begin
            rxd.push_back(pkt_vif.cb.rxd);
            @(pkt_vif.cb);
        end

        pkt_tr.byte2pkt(rxd);
        //pkt_tr.display("Monitor");

        //`callback_macro(packet_monitor_callback, monitor_post_transactor(this, pkt_tr))
        mon2sb_port.write(pkt_tr);
    end
endtask

virtual function void report_phase(uvm_phase phase);
    super.report_phase(phase);
endfunction

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

`endif


./env/packet_env/packet_agent.sv
`ifndef __PACKET_AGENT_SV__
`define __PACKET_AGENT_SV__

`include "packet_sequencer.sv"
`include "packet_driver.sv"
`include "packet_monitor.sv"

class packet_agent extends uvm_agent;
packet_sequencer pkt_sqr;
packet_driver    pkt_drv;
packet_monitor   pkt_mon;

`uvm_component_utils_begin(packet_agent)
    `uvm_field_object(pkt_sqr, UVM_ALL_ON)
    `uvm_field_object(pkt_drv, UVM_ALL_ON)
    `uvm_field_object(pkt_mon, UVM_ALL_ON)
`uvm_component_utils_end

function new(string name, uvm_component parent = null);
    super.new(name, parent);
endfunction

virtual function void build_phase(uvm_phase phase);
    pkt_sqr = packet_sequencer::type_id::create("pkt_sqr", this);
    pkt_drv = packet_driver::type_id::create("pkt_drv", this);
    pkt_mon = packet_monitor::type_id::create("pkt_mon", this);
   
endfunction

virtual function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    pkt_drv.seq_item_port.connect(pkt_sqr.seq_item_export);
endfunction

endclass

`endif


./env/packet_env/packet_rm.sv
`ifndef __PACKET_RM_SV__
`define __PACKET_RM_SV__

class packet_rm extends uvm_component;

logic [9:0] min_pkt_size;
logic [9:0] max_pkt_size;

`uvm_component_utils_begin(packet_rm)
    `uvm_field_int(min_pkt_size, UVM_DEFAULT)
    `uvm_field_int(max_pkt_size, UVM_DEFAULT)
`uvm_component_utils_end

function new(string name, uvm_component parent);
    super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    uvm_config_db#(int)::get(this, "", "min_pkt_size", min_pkt_size);
    uvm_config_db#(int)::get(this, "", "max_pkt_size", max_pkt_size);

    if(min_pkt_size == 0) begin
        min_pkt_size = 32'd64;
    end

    if(max_pkt_size == 0) begin
        max_pkt_size = 32'd512;
    end

endfunction

extern function bit packet_process(ref packet_transaction pkt_tr);

endclass

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_rm.sv"

`uvm_analysis_imp_decl(_rcvd_pkt)
`uvm_analysis_imp_decl(_sent_pkt)

class packet_scoreboard extends uvm_scoreboard;

uvm_analysis_imp_rcvd_pkt #(packet_transaction, packet_scoreboard) mon2sb_port;
uvm_analysis_imp_sent_pkt #(packet_transaction, packet_scoreboard) drv2sb_port;

packet_rm pkt_rm;
packet_transaction ref_pkt_tran[$];

integer error_no = 0;
integer send_no = 0;
integer receive_no = 0;

protected bit disable_scoreboard = 0;
int sbd_error = 0;

`uvm_component_utils_begin(packet_scoreboard)
    `uvm_field_int(disable_scoreboard, UVM_DEFAULT)
`uvm_component_utils_end

function new(string name, uvm_component parent);
    super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);
    mon2sb_port = new("mon2sb", this);
    drv2sb_port = new("drv2sb", this);

    pkt_rm = packet_rm::type_id::create("pkt_rm", this);
endfunction

virtual function void report_phase(uvm_phase phase);
    if(!disable_scoreboard) begin
        `uvm_info(get_type_name(), $sformatf("Reporting scoreboard information...\n%s", this.sprint()), UVM_LOW)
    end
endfunction

virtual function void write_rcvd_pkt(input packet_transaction pkt_tr);
    receive_no++;

    if(ref_pkt_tran.size() > 0) begin
        packet_transaction ref_pkt_tr = ref_pkt_tran.pop_front();

        if(pkt_tr.compare(ref_pkt_tr)) begin
            uvm_report_info(get_type_name(), $psprintf("Sent packet and received packet matched"), UVM_LOW);
        end
        else begin
            error_no++;
            uvm_report_error(get_type_name(), $psprintf("Sent packet and received packet mismatched"), UVM_LOW);

            sbd_error = 1;
        end

        display("[PKT][RECV]");
    end
    else begin
        error_no++;
        display("[PKT][RECV][RECV PKT > SEND PKT]");

        sbd_error = 1;

        uvm_report_error(get_type_name(), $psprintf("No more packets to in the expected queue to compare"), UVM_LOW);
    end

endfunction

virtual function void write_sent_pkt(input packet_transaction pkt_tr);
    bit drop;
    packet_transaction cb_pkt_tr;

    if(!pkt_rm.packet_process(pkt_tr)) begin
        drop = 1;
    end
    else begin
        $cast(cb_pkt_tr, pkt_tr.clone());
        ref_pkt_tran.push_back(pkt_tr);
        send_no++;
        drop = 0;

        display("[PKT][SEND]");
    end

endfunction

function display(string prefix);
    `uvm_info(get_type_name(), $sformatf("%s Send: %d, Receive: %d, Error: %d", prefix, send_no, receive_no, error_no), UVM_NONE);
endfunction

endclass

`endif


./env/packet_env/packet_env.sv
`ifndef __PACKET_ENV_SV__
`define __PACKET_ENV_SV__

`include "packet_agent.sv"
`include "packet_scoreboard.sv"

class packet_env extends uvm_env;

packet_agent      pkt_agt;
packet_scoreboard pkt_sb;

virtual packet_interface pkt_vif;

`uvm_component_utils(packet_env)

function new(string name, uvm_component parent);
    super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    pkt_agt = packet_agent::type_id::create("pkt_agt", this);
    pkt_sb = packet_scoreboard::type_id::create("pkt_sb", this);
endfunction

function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
   
    pkt_agt.pkt_drv.drv2sb_port.connect(pkt_sb.drv2sb_port);
    pkt_agt.pkt_mon.mon2sb_port.connect(pkt_sb.mon2sb_port);
endfunction

task run_phase(uvm_phase phase);
    super.run_phase(phase);
endtask

endclass

`endif


./env/system_virtual_sequencer.sv
`ifndef __SYSTEM_VIRTUAL_SEQUENCER_SV__
`define __SYSTEM_VIRTUAL_SEQUENCER_SV__

`include "cpu_sequencer.sv"
`include "packet_sequencer.sv"

class system_virtual_sequencer extends uvm_sequencer;
cpu_sequencer    cpu_sqr;
packet_sequencer pkt_sqr;

`uvm_component_utils(system_virtual_sequencer)

function new (string name="system_virtual_sequencer", uvm_component parent=null);
    super.new(name, parent);
endfunction

endclass

`endif


./env/env.sv
`ifndef __ENV_SV__
`define __ENV_SV__

`include "cpu_env.sv"
`include "packet_env.sv"
`include "system_virtual_sequencer.sv"

class env extends uvm_env;

cpu_env u_cpu_env;
packet_env u_pkt_env;
system_virtual_sequencer sys_vir_sqr;

`uvm_component_utils(env)

function new(string name, uvm_component parent = null);
    super.new(name, parent);
endfunction

virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    u_cpu_env = cpu_env::type_id::create("u_cpu_env", this);
    u_pkt_env = packet_env::type_id::create("u_packet_env", this);
    sys_vir_sqr = system_virtual_sequencer::type_id::create("sys_vir_sqr", this);
endfunction

function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);

    sys_vir_sqr.cpu_sqr = u_cpu_env.cpu_agt.cpu_sqr;
    sys_vir_sqr.pkt_sqr = u_pkt_env.pkt_agt.pkt_sqr;
endfunction

function void end_of_elaboration_phase(uvm_phase phase);
    super.end_of_elaboration_phase(phase);
endfunction

task run_phase(uvm_phase phase);
    super.run_phase(phase);
endtask

endclass

`endif


./sequence/cpu_interface_sequence/cpu_base_sequence.sv
`ifndef _CPU_BASE_SEQUENCE_SV__
`define _CPU_BASE_SEQUENCE_SV__

virtual class cpu_base_sequence extends uvm_sequence #(cpu_transaction);

function new(string name="cpu_base_sequence");
    super.new(name);
    set_automatic_phase_objection(1);
endfunction
 
endclass

class read_word_seq extends cpu_base_sequence;

function new(string name="read_word_seq");
    super.new(name);
endfunction
 
`uvm_object_utils(read_word_seq)

rand logic [7:0] raddr;

virtual task body();
    `uvm_do_with(req, {req.addr == raddr; req.rw == cpu_transaction::READ; req.dout == 32'h0;} )
endtask

endclass

class write_word_seq extends cpu_base_sequence;

function new(string name="write_word_seq");
    super.new(name);
endfunction
 
`uvm_object_utils(write_word_seq)

rand logic [7:0] waddr;
rand logic [31:0] wdout;

virtual task body();
    `uvm_do_with(req, {req.addr == waddr; req.rw == cpu_transaction::WRITE; req.dout == wdout;} )
endtask

endclass

`endif


./sequence/cpu_interface_sequence/cpu_sequence.sv
`ifndef __CPU_WRITE_AND_READ_SV__
`define __CPU_WRITE_AND_READ_SV__

`include "cpu_base_sequence.sv"

class cpu_write_and_read extends cpu_base_sequence;

read_word_seq r_seq;
write_word_seq w_seq;

logic [9:0] min_pkt_size;
logic [9:0] max_pkt_size;

`uvm_declare_p_sequencer(system_virtual_sequencer)

`uvm_object_utils(cpu_write_and_read)

function new(string name="cpu_write_and_read");
    super.new(name);

    uvm_config_db#(int)::get(uvm_root::get(), "", "min_pkt_size", min_pkt_size);
    uvm_config_db#(int)::get(uvm_root::get(), "", "max_pkt_size", max_pkt_size);

    if(min_pkt_size == 0) begin
        min_pkt_size = 32'd64;
    end

    if(max_pkt_size == 0) begin
        max_pkt_size = 32'd512;
    end

endfunction : new

virtual task body();
    `uvm_do_on_with(w_seq, p_sequencer.cpu_sqr, {w_seq.waddr == 8'h4; w_seq.wdout == 'd65;})
    `uvm_do_on_with(r_seq, p_sequencer.cpu_sqr, {r_seq.raddr == 8'h4;})
    `uvm_do_on_with(w_seq, p_sequencer.cpu_sqr, {w_seq.waddr == 8'h8; w_seq.wdout == 'd500;})
    `uvm_do_on_with(r_seq, p_sequencer.cpu_sqr, {r_seq.raddr == 8'h8;})
    `uvm_do_on_with(w_seq, p_sequencer.cpu_sqr, {w_seq.waddr == 8'h0; w_seq.wdout == 'h1;})
    `uvm_do_on_with(r_seq, p_sequencer.cpu_sqr, {r_seq.raddr == 8'h0;})
endtask : body

endclass

class cpu_write_and_read1 extends cpu_base_sequence;

read_word_seq r_seq;
write_word_seq w_seq;

logic [9:0] min_pkt_size;
logic [9:0] max_pkt_size;

`uvm_object_utils(cpu_write_and_read1)

function new(string name="cpu_write_and_read1");
    super.new(name);

    uvm_config_db#(int)::get(uvm_root::get(), "", "min_pkt_size", min_pkt_size);
    uvm_config_db#(int)::get(uvm_root::get(), "", "max_pkt_size", max_pkt_size);

    if(min_pkt_size == 0) begin
        min_pkt_size = 32'd64;
    end

    if(max_pkt_size == 0) begin
        max_pkt_size = 32'd512;
    end

endfunction : new

virtual task body();
    `uvm_do_with(w_seq, {w_seq.waddr == 8'h4; w_seq.wdout == 'd65;})
    `uvm_do_with(r_seq, {r_seq.raddr == 8'h4;})
    `uvm_do_with(w_seq, {w_seq.waddr == 8'h8; w_seq.wdout == 'd500;})
    `uvm_do_with(r_seq, {r_seq.raddr == 8'h8;})
    `uvm_do_with(w_seq, {w_seq.waddr == 8'h0; w_seq.wdout == 'h1;})
    `uvm_do_with(r_seq, {r_seq.raddr == 8'h0;})
endtask : body

endclass


`endif


./sequence/packet_sequence/packet_base_sequence.sv
`ifndef _PACKET_BASE_SEQUENCE_SV__
`define _PACKET_BASE_SEQUENCE_SV__

virtual class packet_base_sequence extends uvm_sequence #(packet_transaction);

function new(string name="packet_base_sequence");
    super.new(name);
    set_automatic_phase_objection(1);
endfunction
 
endclass

class send_one_pkt_seq extends packet_base_sequence;

function new(string name="send_one_pkt_seq");
    super.new(name);
endfunction
 
`uvm_object_utils(send_one_pkt_seq)

rand packet_transaction::head_type     pkt_head_type     ;
rand packet_transaction::packet_length pkt_packet_length ;
rand logic [6:0 ]                      frame_interval    ;

virtual task body();
    `uvm_do_with(req, {req.pkt_head_type == pkt_head_type; req.pkt_packet_length == pkt_packet_length; req.frame_interval == frame_interval;} )
endtask
 
endclass

`endif


./sequence/packet_sequence/packet_sequence.sv
`ifndef __PACKET_SEND_PACKETS_SV__
`define __PACKET_SEND_PACKETS_SV__

`include "packet_base_sequence.sv"

class packet_send_packets extends packet_base_sequence;

int itr = 100;
send_one_pkt_seq pkt_seq;

`uvm_declare_p_sequencer(system_virtual_sequencer)

`uvm_object_utils(packet_send_packets)

function new(string name="packet_send_packets");
    super.new(name);
endfunction

virtual task body();
    //void'(uvm_config_db#(int)::get(null,get_full_name(),"itr", itr));
    `uvm_info(get_type_name(), $sformatf("%s starting...itr = %0d", get_sequence_path(), itr), UVM_NONE);
    for(int i = 0; i < itr; i++) begin
        `uvm_do_on(pkt_seq, p_sequencer.pkt_sqr)
    end
endtask : body

endclass

class packet_send_packets1 extends packet_base_sequence;

int itr = 100;
send_one_pkt_seq pkt_seq;

`uvm_object_utils(packet_send_packets1)

function new(string name="packet_send_packets1");
    super.new(name);
endfunction

virtual task body();
    //void'(uvm_config_db#(int)::get(null,get_full_name(),"itr", itr));
    `uvm_info(get_type_name(), $sformatf("%s starting...itr = %0d", get_sequence_path(), itr), UVM_NONE);
    for(int i = 0; i < itr; i++) begin
        `uvm_do(pkt_seq)
    end
endtask : body

endclass

`endif


./sequence/system_sequence.sv
`ifndef __SYSTEM_SEQUENCE_SV__
`define __SYSTEM_SEQUENCE_SV__

`include "cpu_transaction.sv"
`include "cpu_sequence.sv"
`include "packet_sequence.sv"

//class cpu_rw_and_send_pkts extends uvm_sequence #(uvm_sequence_item);
class cpu_rw_and_send_pkts extends cpu_base_sequence;

cpu_write_and_read  cpu_rw;
packet_send_packets send_pkts;

`uvm_object_utils(cpu_rw_and_send_pkts)

function new(string name="cpu_write_and_read");
    super.new(name);

    cpu_rw    = new("cpu configuration");
    send_pkts = new("send packets");
endfunction

virtual task body();
    `uvm_do(cpu_rw)
    `uvm_do(send_pkts)
endtask

endclass

class cpu_rw_and_send_pkts1 extends cpu_base_sequence;

cpu_write_and_read1  cpu_rw;
packet_send_packets1 send_pkts;

`uvm_declare_p_sequencer(system_virtual_sequencer)

`uvm_object_utils(cpu_rw_and_send_pkts1)

function new(string name="cpu_rw_and_send_pkts1");
    super.new(name);

    cpu_rw    = new("cpu configuration");
    send_pkts = new("send packets");
endfunction

virtual task body();
    `uvm_do_on(cpu_rw, p_sequencer.cpu_sqr)
    `uvm_do_on(send_pkts, p_sequencer.pkt_sqr)
endtask

endclass

`endif


./test/test.sv
`ifndef __TEST_SV__
`define __TEST_SV__

`include "env.sv"
`include "cpu_sequence.sv"
`include "packet_sequence.sv"
`include "system_sequence.sv"

class base_test extends uvm_test;

env tb_env;
bit test_pass = 1;
uvm_table_printer printer;

`uvm_component_utils(base_test)

function new(string name="base_test", uvm_component parent=null);
    super.new(name, parent);

    uvm_config_db#(int)::set(uvm_root::get(), "*", "min_pkt_size", 'd65);
    uvm_config_db#(int)::set(uvm_root::get(), "*", "max_pkt_size", 'd500);

endfunction

virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    tb_env = env::type_id::create("tb_env", this);
    printer = new();
endfunction

function void end_of_elaboration_phase(uvm_phase phase);
    super.end_of_elaboration_phase(phase);
    `uvm_info(get_type_name(),$sformatf("Printing the test topology :\n%s", this.sprint(printer)), UVM_LOW)
endfunction

task run_phase(uvm_phase phase);
    super.run_phase(phase);
endtask

function void extract_phase(uvm_phase phase);
    super.extract_phase(phase);

    if(tb_env.u_cpu_env.cpu_sb.sbd_error || tb_env.u_pkt_env.pkt_sb.sbd_error || tb_env.u_pkt_env.pkt_sb.ref_pkt_tran.size() != 0) begin
        test_pass = 0;
    end

endfunction

function void report_phase(uvm_phase phase);
    super.report_phase(phase);

    if(test_pass) begin
        `uvm_info(get_type_name(), "** UVM TEST PASSED **", UVM_NONE)
    end
    else begin
        `uvm_error(get_type_name(), "** UVM TEST FAIL **")
    end
endfunction

endclass

class test extends base_test;

`uvm_component_utils(test)

function new(string name="test", uvm_component parent=null);
    super.new(name, parent);
endfunction

virtual function void build_phase(uvm_phase phase);
    cpu_rw_and_send_pkts cpu_and_pkt;

    super.build_phase(phase);

    cpu_and_pkt = cpu_rw_and_send_pkts::type_id::create();
    uvm_config_db#(uvm_sequence_base)::set(this, "tb_env.sys_vir_sqr.main_phase", "default_sequence", cpu_and_pkt);
endfunction

endclass

class test3 extends base_test;

`uvm_component_utils(test3)

function new(string name="test3", uvm_component parent=null);
    super.new(name, parent);
endfunction

virtual function void build_phase(uvm_phase phase);
    cpu_rw_and_send_pkts1 cpu_and_pkt;

    super.build_phase(phase);

    cpu_and_pkt = cpu_rw_and_send_pkts1::type_id::create();
    uvm_config_db#(uvm_sequence_base)::set(this, "tb_env.sys_vir_sqr.main_phase", "default_sequence", cpu_and_pkt);
endfunction

endclass

`endif


./env/top.sv
`timescale 1ns/1ps

`include "uvm_macros.svh"
import uvm_pkg::*;

`include "cpu_interface.svi"
`include "packet_interface.svi"
`include "test.sv"

module top;
parameter clock_cycle = 10;

logic clk;
logic rst_n;

cpu_interface cpu_intf(clk, rst_n);
packet_interface pkt_intf(clk, rst_n);

dut u_dut (
    .clk    (clk             ) ,
    .rst_n  (rst_n           ) ,

    .addr   (cpu_intf.addr   ) ,
    .rw     (cpu_intf.rw     ) ,
    .enable (cpu_intf.enable ) ,
    .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

initial begin
    rst_n = 1'b1;
    repeat(10) @(posedge clk);
    rst_n = 1'b0;
    repeat(10) @(posedge clk);
    rst_n = 1'b1;
end

initial begin
    uvm_config_db#(virtual cpu_interface)::set(uvm_root::get(), "*", "cpu_vif", cpu_intf);
    uvm_config_db#(virtual packet_interface)::set(uvm_root::get(), "*", "pkt_vif", pkt_intf);
    run_test();
end

`ifdef WAVE_ON
initial begin
    //$dumpfile("wave.vcd");
    //$dumpvars(0, top);
end
`endif

endmodule


./script/do.tcl
add wave -r /*
run -all
exit

./script/Makefile

ifeq ($(GUI), 1)
    GUI_ARG = -gui
endif

PROJECT_DIR = /mnt/uvm
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)

SEQUENCE_DIR = $(PROJECT_DIR)/sequence
INCDIR += +incdir+$(SEQUENCE_DIR)

CPU_SEQUENCE_DIR = $(SEQUENCE_DIR)/cpu_interface_sequence
INCDIR += +incdir+$(CPU_SEQUENCE_DIR)

PACKET_SEQUENCE_DIR = $(SEQUENCE_DIR)/packet_sequence
INCDIR += +incdir+$(PACKET_SEQUENCE_DIR)

UVM_TB_TOP = $(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

UVM_COMPILE_ARG = +incdir+/mnt/uvm/uvm-1.2/src /mnt/uvm/uvm-1.2/src/uvm.sv

COMPILE_ARG = -sv -novopt
COMPILE_ARG += $(UVM_COMPILE_ARG) $(INCDIR) $(COMPILE_LOG_ARG) $(WAVE_ARG)

RUN_LOG_ARG = -l simv.log

SCRIPT_DIR = $(PROJECT_DIR)/script
RUN_TCL = $(SCRIPT_DIR)/do.tcl

RUN_ARG  = $(RUN_LOG_ARG) $(GUI_ARG)
RUN_ARG += +UVM_TESTNAME=test +UVM_VERBOSITY=UVM_FULL -c -novopt -sv_lib lib/uvm_dpi work.top -do $(RUN_TCL) -wlf wave.wlf

SEED = 1

MIT_HOME = /home/tools/questasim/questasim/include
UVM_DPI_DIR = /mnt/uvm/uvm-1.2/src/dpi
UVM_DPI_FILE = /mnt/uvm/uvm-1.2/src/dpi/uvm_dpi.cc

UVM_DPI_COMPILE_ARG = -m32 -fPIC -DQUESTA -g -W -shared
UVM_DPI_COMPILE_ARG += -I$(MIT_HOME) -I$(UVM_DPI_DIR) $(UVM_DPI_FILE)

default: test

test: lib/uvm_dpi.so compile run

run:
 vsim $(RUN_ARG)

compile:
 if [ ! -d work ]; then vlib work; fi;
 vlog $(COMPILE_ARG) $(UVM_TB_TOP) $(RTL)

lib/uvm_dpi.so:
 if [ ! -d lib ]; then mkdir lib; fi
 g++ $(UVM_DPI_COMPILE_ARG) -o $@

clean:
 rm -rf simv simv.* *log


Friday, November 21, 2014

virtualbox command to change configuration of virtual machine

1) change the disk size of centos4
http://scott2595.blogspot.com/2014/02/change-size-of-hard-disk-of-virtual.html

2) command to resize a vdi disk
VBoxManage.exe modifyhd ubuntu12_copy.vdi --resize 100000

3) command to clone a vdi disk
http://scott2595.blogspot.com/2014/02/vboxmanagevbox.html

4) command to change the uuid of a vdi disk
VBoxManage.exe internalcommands sethduuid  ubuntu12_copy.vdi

5) command to compact a vdi disk
In linux virtual machine:
sudo dd if=/dev/zero of=/bigemptyfile bs=4096k
sudo rm -rf /bigemptyfile

In host:
VBoxManage.exe modifyhd ubuntu12_copy.vdi --compact