Skip to content

Commit

Permalink
Merge branch 'marushchenko_feature_uvm-crdt_agent' into 'main'
Browse files Browse the repository at this point in the history
UVM AVST_CRDT AGENT [FEATURE]: add agent

See merge request ndk/ofm!389
  • Loading branch information
jakubcabal committed Aug 9, 2024
2 parents 591ab9f + 38c396d commit b2c39c9
Show file tree
Hide file tree
Showing 12 changed files with 836 additions and 0 deletions.
8 changes: 8 additions & 0 deletions comp/uvm/avst_crdt/Modules.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Modules.tcl: Local include script
# Copyright (C) 2024 CESNET z. s. p. o.
# Author(s): Yaroslav Marushchenko <[email protected]>

# SPDX-License-Identifier: BSD-3-Clause

lappend MOD "$ENTITY_BASE/interface.sv"
lappend MOD "$ENTITY_BASE/pkg.sv"
189 changes: 189 additions & 0 deletions comp/uvm/avst_crdt/agent.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// agent.sv: AVST credit control agent
// Copyright (C) 2024 CESNET z. s. p. o.
// Author(s): Yaroslav Marushchenko <[email protected]>

// SPDX-License-Identifier: BSD-3-Clause

// ======= //
// RX side //
// ======= //

class agent_rx #(int unsigned UPDATE_CNT_WIDTH) extends uvm_agent;
`uvm_component_param_utils(uvm_avst_crdt::agent_rx #(UPDATE_CNT_WIDTH))

// Analysis port
uvm_analysis_port #(sequence_item #(UPDATE_CNT_WIDTH)) analysis_port;

// ------------------ //
// Agent's components //
// ------------------ //

sequencer #(UPDATE_CNT_WIDTH) m_sequencer;
driver_rx #(UPDATE_CNT_WIDTH) m_driver;
monitor #(UPDATE_CNT_WIDTH) m_monitor;
config_item m_config;

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

virtual function uvm_active_passive_enum get_is_active();
return uvm_active_passive_enum'(m_config.active);
endfunction

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

// Get a configuration from the database
assert(uvm_config_db #(config_item)::get(this, "", "m_config", m_config))
else begin
`uvm_fatal(this.get_full_name(), "Unable to get configuration object")
end

// Create a sequencer and a driver if the agent is active
if(get_is_active() == UVM_ACTIVE) begin
m_sequencer = sequencer #(UPDATE_CNT_WIDTH)::type_id::create("m_sequencer", this);
m_driver = driver_rx #(UPDATE_CNT_WIDTH)::type_id::create("m_driver", this);
end

// Create a monitor
m_monitor = monitor #(UPDATE_CNT_WIDTH)::type_id::create("m_monitor", this);
endfunction

function void connect_phase(uvm_phase phase);
// Virtual interface
virtual avst_crdt_if #(UPDATE_CNT_WIDTH) vif;

super.connect_phase(phase);

// Get a virtual interface instance from the database
assert(uvm_config_db #(virtual avst_crdt_if #(UPDATE_CNT_WIDTH))::get(null, "", m_config.interface_name, vif))
else begin
`uvm_fatal(this.get_full_name(), $sformatf("Cannot find an interface with name %s, probably not set!", m_config.interface_name));
end

// Connect the driver if the agent is active
if(get_is_active() == UVM_ACTIVE) begin
m_driver.vif = vif;
m_driver.seq_item_port.connect(m_sequencer.seq_item_export);
end

// Connect the monitor
m_monitor.vif = vif;
analysis_port = m_monitor.analysis_port;
endfunction

endclass

class agent_rx_hdr extends agent_rx #(2);
`uvm_component_utils(uvm_avst_crdt::agent_rx_hdr)

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

endclass

class agent_rx_data extends agent_rx #(4);
`uvm_component_utils(uvm_avst_crdt::agent_rx_data)

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

endclass

// ======= //
// TX side //
// ======= //

class agent_tx #(int unsigned UPDATE_CNT_WIDTH) extends uvm_agent;
`uvm_component_param_utils(uvm_avst_crdt::agent_tx #(UPDATE_CNT_WIDTH))

// Analysis port
uvm_analysis_port #(sequence_item #(UPDATE_CNT_WIDTH)) analysis_port;

// ------------------ //
// Agent's components //
// ------------------ //

sequencer #(UPDATE_CNT_WIDTH) m_sequencer;
driver_tx #(UPDATE_CNT_WIDTH) m_driver;
monitor #(UPDATE_CNT_WIDTH) m_monitor;
config_item m_config;

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

virtual function uvm_active_passive_enum get_is_active();
return uvm_active_passive_enum'(m_config.active);
endfunction

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

// Get a configuration from the database
assert(uvm_config_db #(config_item)::get(this, "", "m_config", m_config))
else begin
`uvm_fatal(this.get_full_name(), "Unable to get configuration object")
end

// Create a sequencer and a driver if the agent is active
if(get_is_active() == UVM_ACTIVE) begin
m_sequencer = sequencer #(UPDATE_CNT_WIDTH)::type_id::create("m_sequencer", this);
m_driver = driver_tx #(UPDATE_CNT_WIDTH)::type_id::create("m_driver", this);
end

// Create a monitor
m_monitor = monitor #(UPDATE_CNT_WIDTH)::type_id::create("m_monitor", this);
endfunction

function void connect_phase(uvm_phase phase);
// Virtual interface
virtual avst_crdt_if #(UPDATE_CNT_WIDTH) vif;

super.connect_phase(phase);

// Get a virtual interface instance from the database
assert(uvm_config_db #(virtual avst_crdt_if #(UPDATE_CNT_WIDTH))::get(null, "", m_config.interface_name, vif))
else begin
`uvm_fatal(this.get_full_name(), $sformatf("Cannot find an interface with name %s, probably not set!", m_config.interface_name));
end

// Connect the driver if the agent is active
if(get_is_active() == UVM_ACTIVE) begin
m_driver.vif = vif;
m_driver.seq_item_port.connect(m_sequencer.seq_item_export);
end

// Connect the monitor
m_monitor.vif = vif;
analysis_port = m_monitor.analysis_port;
endfunction

endclass

class agent_tx_hdr extends agent_tx #(2);
`uvm_component_utils(uvm_avst_crdt::agent_tx_hdr)

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

endclass

class agent_tx_data extends agent_tx #(4);
`uvm_component_utils(uvm_avst_crdt::agent_tx_data)

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

endclass
27 changes: 27 additions & 0 deletions comp/uvm/avst_crdt/config.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// config.sv: Configuration object for AVST credit control agent
// Copyright (C) 2024 CESNET z. s. p. o.
// Author(s): Yaroslav Marushchenko <[email protected]>

// SPDX-License-Identifier: BSD-3-Clause

`ifndef AVST_CRDT_CONFIG_SV
`define AVST_CRDT_CONFIG_SV

class config_item extends uvm_object;
`uvm_object_utils(uvm_avst_crdt::config_item)

// ----------------------- //
// Configuration variables //
// ----------------------- //

uvm_active_passive_enum active;
string interface_name;

// Constructor
function new(string name = "config_item");
super.new(name);
endfunction

endclass

`endif
103 changes: 103 additions & 0 deletions comp/uvm/avst_crdt/driver.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// driver.sv: AVST credit control driver
// Copyright (C) 2024 CESNET z. s. p. o.
// Author(s): Yaroslav Marushchenko <[email protected]>

// SPDX-License-Identifier: BSD-3-Clause

// ======= //
// RX side //
// ======= //

class driver_rx #(int unsigned UPDATE_CNT_WIDTH) extends uvm_driver #(sequence_item #(UPDATE_CNT_WIDTH));
`uvm_component_param_utils(uvm_avst_crdt::driver_rx #(UPDATE_CNT_WIDTH))

// Virtual interface
virtual avst_crdt_if #(UPDATE_CNT_WIDTH).driver_rx vif;

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

// Driving signals to interface
task run_phase(uvm_phase phase);
rsp = sequence_item #(UPDATE_CNT_WIDTH)::type_id::create("rsp");

forever begin
// Get new sequence item to drive to interface
seq_item_port.try_next_item(req);

if (req != null) begin
vif.driver_rx_cb.INIT <= req.init;
vif.driver_rx_cb.UPDATE <= req.update;
vif.driver_rx_cb.UPDATE_CNT <= req.update_cnt;
seq_item_port.item_done();
end else begin
vif.driver_rx_cb.INIT <= 1'b0;
vif.driver_rx_cb.UPDATE <= 1'b0;
vif.driver_rx_cb.UPDATE_CNT <= 1'bX;
end

// Wait for the clocking block to write values
@(vif.driver_rx_cb);

if (req != null) begin
// Set response data
rsp.copy(req);
rsp.init_ack = vif.driver_rx_cb.INIT_ACK;

rsp.set_id_info(req);
seq_item_port.put_response(rsp);
end
end
endtask

endclass

// ======= //
// TX side //
// ======= //

class driver_tx #(int unsigned UPDATE_CNT_WIDTH) extends uvm_driver #(sequence_item #(UPDATE_CNT_WIDTH));
`uvm_component_param_utils(uvm_avst_crdt::driver_tx #(UPDATE_CNT_WIDTH))

// Virtual interface
virtual avst_crdt_if #(UPDATE_CNT_WIDTH).driver_tx vif;

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

// Start driving signals to interface
task run_phase(uvm_phase phase);
rsp = sequence_item #(UPDATE_CNT_WIDTH)::type_id::create("rsp");

forever begin
// Get new sequence item to drive to interface
seq_item_port.try_next_item(req);

if (req != null) begin
vif.driver_tx_cb.INIT_ACK <= req.init_ack;
seq_item_port.item_done();
end else begin
vif.driver_tx_cb.INIT_ACK <= 1'b0;
end

// Wait for the clocking block to write values
@(vif.driver_tx_cb);

if (req != null) begin
// Set response data
rsp.copy(req);
rsp.init = vif.driver_tx_cb.INIT;
rsp.update = vif.driver_tx_cb.UPDATE;
rsp.update_cnt = vif.driver_tx_cb.UPDATE_CNT;

rsp.set_id_info(req);
seq_item_port.put_response(rsp);
end
end
endtask

endclass
54 changes: 54 additions & 0 deletions comp/uvm/avst_crdt/interface.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// interface.sv: AVST credit control interface
// Copyright (C) 2024 CESNET z. s. p. o.
// Author(s): Yaroslav Marushchenko <[email protected]>

// SPDX-License-Identifier: BSD-3-Clause

interface avst_crdt_if #(int unsigned UPDATE_CNT_WIDTH) (input logic CLK);
// ------------------------------- //
// Bus structure of credit control //
// ------------------------------- //

wire logic INIT;
wire logic INIT_ACK;
wire logic UPDATE;
wire logic [UPDATE_CNT_WIDTH-1 : 0] UPDATE_CNT;

// RX driver clocking block
clocking driver_rx_cb @(posedge CLK);
input INIT_ACK;
output INIT, UPDATE, UPDATE_CNT;
endclocking

// TX driver clocking block
clocking driver_tx_cb @(posedge CLK);
output INIT_ACK;
input INIT, UPDATE, UPDATE_CNT;
endclocking

// Monitor clocking block
clocking monitor_cb @(posedge CLK);
input INIT, INIT_ACK, UPDATE, UPDATE_CNT;
endclocking

// RX connection to DUT
modport dut_rx(
input INIT, UPDATE, UPDATE_CNT,
output INIT_ACK
);

// TX connection to DUT
modport dut_tx(
input INIT_ACK,
output INIT, UPDATE, UPDATE_CNT
);

// RX driver module port
modport driver_rx(clocking driver_rx_cb);
// TX driver module port
modport driver_tx(clocking driver_tx_cb);

// Monitor module port
modport monitor(clocking monitor_cb);

endinterface
Loading

0 comments on commit b2c39c9

Please sign in to comment.