mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-24 22:07:43 -04:00
Update lowrisc_ip to lowRISC/opentitan@7c4f8b3fd
Update code from upstream repository https://github.com/lowRISC/opentitan to revision 7c4f8b3fde4bb625ac3330ff52d3f66507190fe5 Please note that we're adding push_pull_agent for the first time in this commit. Signed-off-by: Prajwala Puttappa <prajwalaputtappa@lowrisc.org>
This commit is contained in:
parent
be5fffa656
commit
c900ef1476
18 changed files with 1257 additions and 0 deletions
13
vendor/lowrisc_ip/dv/sv/push_pull_agent/README.md
vendored
Normal file
13
vendor/lowrisc_ip/dv/sv/push_pull_agent/README.md
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
# PUSH_PULL UVM Agent
|
||||
|
||||
PUSH_PULL UVM Agent is extended from DV library agent classes.
|
||||
|
||||
## Description
|
||||
|
||||
This agent implements both Push (ready/valid) and Pull (req/ack) interface
|
||||
protocols, and can be configured to behave in both host and device modes.
|
||||
|
||||
The agent configuration object (`push_pull_agent_cfg`) contains an enum `agent_type`
|
||||
that is used to select either push or pull modes.
|
||||
To configure the agent to use the ready/valid protocol, set `agent_type = PushAgent`, and
|
||||
to configure the agent to use the req/ack protocol, set `agent_type = PullAgent`.
|
32
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent.core
vendored
Normal file
32
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent.core
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
CAPI=2:
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
name: "lowrisc:dv:push_pull_agent:0.1"
|
||||
description: "PUSH_PULL DV UVM agent"
|
||||
filesets:
|
||||
files_dv:
|
||||
depend:
|
||||
- lowrisc:dv:dv_utils
|
||||
- lowrisc:dv:dv_lib
|
||||
files:
|
||||
- push_pull_if.sv
|
||||
- push_pull_agent_pkg.sv
|
||||
- push_pull_item.sv: {is_include_file: true}
|
||||
- push_pull_agent_cfg.sv: {is_include_file: true}
|
||||
- push_pull_agent_cov.sv: {is_include_file: true}
|
||||
- push_pull_driver_lib.sv: {is_include_file: true}
|
||||
- push_pull_monitor.sv: {is_include_file: true}
|
||||
- push_pull_sequencer.sv: {is_include_file: true}
|
||||
- push_pull_agent.sv: {is_include_file: true}
|
||||
- seq_lib/push_pull_base_seq.sv: {is_include_file: true}
|
||||
- seq_lib/push_pull_host_seq.sv: {is_include_file: true}
|
||||
- seq_lib/push_pull_indefinite_host_seq.sv: {is_include_file: true}
|
||||
- seq_lib/push_pull_device_seq.sv: {is_include_file: true}
|
||||
- seq_lib/push_pull_seq_list.sv: {is_include_file: true}
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_dv
|
54
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent.sv
vendored
Normal file
54
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent.sv
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class push_pull_agent #(
|
||||
parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth
|
||||
) extends dv_base_agent #(
|
||||
.CFG_T (push_pull_agent_cfg#(HostDataWidth, DeviceDataWidth)),
|
||||
.DRIVER_T (push_pull_driver#(HostDataWidth, DeviceDataWidth)),
|
||||
.SEQUENCER_T(push_pull_sequencer#(HostDataWidth, DeviceDataWidth)),
|
||||
.MONITOR_T (push_pull_monitor#(HostDataWidth, DeviceDataWidth)),
|
||||
.COV_T (push_pull_agent_cov#(HostDataWidth, DeviceDataWidth))
|
||||
);
|
||||
|
||||
`uvm_component_param_utils(push_pull_agent#(HostDataWidth, DeviceDataWidth))
|
||||
|
||||
`uvm_component_new
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
|
||||
// use for reactive device
|
||||
cfg.has_req_fifo = 1;
|
||||
|
||||
// get push_pull_if handle
|
||||
if (!uvm_config_db#(virtual push_pull_if#(HostDataWidth, DeviceDataWidth))::get(
|
||||
this, "", "vif", cfg.vif)) begin
|
||||
`uvm_fatal(`gfn, "failed to get push_pull_if handle from uvm_config_db")
|
||||
end
|
||||
cfg.vif.if_mode = cfg.if_mode;
|
||||
cfg.vif.is_push_agent = (cfg.agent_type == PushAgent);
|
||||
cfg.vif.in_bidirectional_mode = cfg.in_bidirectional_mode;
|
||||
cfg.vif.is_pull_handshake_4_phase = (cfg.pull_handshake_type == FourPhase);
|
||||
endfunction
|
||||
|
||||
function void connect_phase(uvm_phase phase);
|
||||
super.connect_phase(phase);
|
||||
if (cfg.if_mode == dv_utils_pkg::Device) begin
|
||||
monitor.req_analysis_port.connect(sequencer.req_analysis_fifo.analysis_export);
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual task run_phase(uvm_phase phase);
|
||||
push_pull_device_seq#(HostDataWidth, DeviceDataWidth) m_seq =
|
||||
push_pull_device_seq#(HostDataWidth, DeviceDataWidth)::type_id::create("m_seq", this);
|
||||
if (cfg.if_mode == dv_utils_pkg::Device && cfg.start_default_device_seq) begin
|
||||
uvm_config_db#(uvm_object_wrapper)::set(null, {sequencer.get_full_name(), ".run_phase"},
|
||||
"default_sequence", m_seq.get_type());
|
||||
sequencer.start_phase_sequence(phase);
|
||||
end
|
||||
endtask
|
||||
|
||||
endclass
|
207
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent_cfg.sv
vendored
Normal file
207
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent_cfg.sv
vendored
Normal file
|
@ -0,0 +1,207 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class push_pull_agent_cfg #(parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth)
|
||||
extends dv_base_agent_cfg;
|
||||
|
||||
// interface handle used by driver, monitor & the sequencer, via cfg handle
|
||||
virtual push_pull_if#(HostDataWidth, DeviceDataWidth) vif;
|
||||
|
||||
// Determines whether this agent is configured as push or pull.
|
||||
// Should be set from the IP level environment.
|
||||
push_pull_agent_e agent_type;
|
||||
|
||||
// Indicates the type of req-ack handshake.
|
||||
pull_handshake_e pull_handshake_type;
|
||||
|
||||
// Configures the agent to act in bidirectional mode,
|
||||
// transferring data on both sides of the handshake.
|
||||
bit in_bidirectional_mode;
|
||||
|
||||
// A knob to keep the data until next req, rather than driving unknown after handshake
|
||||
// completes. See #4465 for the detailed discussion
|
||||
bit hold_h_data_until_next_req;
|
||||
bit hold_d_data_until_next_req;
|
||||
|
||||
// Host-side delay range for both Push/Pull protocols.
|
||||
rand int unsigned host_delay_min;
|
||||
rand int unsigned host_delay_max;
|
||||
|
||||
// Device-side delay range for both Push/Pull protocols.
|
||||
rand int unsigned device_delay_min;
|
||||
rand int unsigned device_delay_max;
|
||||
|
||||
// 4-phase pull protocol delay ranges to de-assert req & ack.
|
||||
rand int unsigned req_lo_delay_min;
|
||||
rand int unsigned req_lo_delay_max;
|
||||
rand int unsigned ack_lo_delay_min;
|
||||
rand int unsigned ack_lo_delay_max;
|
||||
|
||||
// Enables/disable all protocol delays.
|
||||
rand bit zero_delays;
|
||||
|
||||
// Enable starting the device sequence by default if configured in Device mode.
|
||||
bit start_default_device_seq = 1;
|
||||
|
||||
// These data queues allows users to specify data to be driven by the sequence at a higher level.
|
||||
//
|
||||
// To specify some Host data to be sent, `set_h_user_data()` should be called from a higher layer
|
||||
// to push the specified user data into the `h_user_data_q` queue.
|
||||
// The Host sequence will then check if the queue has any data in it, if so it will pop off the
|
||||
// first entry and drive that data value.
|
||||
//
|
||||
// Similarly, `set_d_user_data()` should be called from a higher layer to push some specified
|
||||
// user data into the `d_user_data_q` queue, which will then be popped off and driven by the
|
||||
// Device sequence.
|
||||
local bit [HostDataWidth-1:0] h_user_data_q[$];
|
||||
local bit [DeviceDataWidth-1:0] d_user_data_q[$];
|
||||
|
||||
constraint host_delay_min_c {
|
||||
soft host_delay_min == 0;
|
||||
}
|
||||
|
||||
constraint host_delay_max_c {
|
||||
solve zero_delays before host_delay_max;
|
||||
if (zero_delays) {
|
||||
host_delay_max == 0;
|
||||
} else {
|
||||
host_delay_max dist {
|
||||
[1:10] :/ 1,
|
||||
[11:50] :/ 4,
|
||||
[51:100] :/ 3,
|
||||
[101:500] :/ 2,
|
||||
[501:1000] :/ 1
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
constraint device_delay_min_c {
|
||||
soft device_delay_min == 0;
|
||||
}
|
||||
|
||||
constraint device_delay_max_c {
|
||||
solve zero_delays before device_delay_max;
|
||||
if (zero_delays) {
|
||||
device_delay_max == 0;
|
||||
} else {
|
||||
device_delay_max dist {
|
||||
[1:10] :/ 1,
|
||||
[11:50] :/ 4,
|
||||
[51:100] :/ 3,
|
||||
[101:500] :/ 2,
|
||||
[501:1000] :/ 1
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
constraint req_lo_delay_min_c {
|
||||
soft req_lo_delay_min == 0;
|
||||
}
|
||||
|
||||
constraint req_lo_delay_max_c {
|
||||
solve zero_delays before req_lo_delay_max;
|
||||
if (zero_delays) {
|
||||
req_lo_delay_max == 0;
|
||||
} else {
|
||||
req_lo_delay_max dist {
|
||||
[1:10] :/ 1,
|
||||
[11:50] :/ 4,
|
||||
[51:100] :/ 3
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
constraint ack_lo_delay_min_c {
|
||||
soft ack_lo_delay_min == 0;
|
||||
}
|
||||
|
||||
constraint ack_lo_delay_max_c {
|
||||
solve zero_delays before ack_lo_delay_max;
|
||||
if (zero_delays) {
|
||||
ack_lo_delay_max == 0;
|
||||
} else {
|
||||
ack_lo_delay_max dist {
|
||||
[1:10] :/ 1,
|
||||
[11:50] :/ 4,
|
||||
[51:100] :/ 3
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Bias randomization in favor of enabling zero delays less often.
|
||||
constraint zero_delays_c {
|
||||
zero_delays dist { 0 := 7,
|
||||
1 := 3 };
|
||||
}
|
||||
|
||||
// Setter method for the user data queues - must be called externally to place specific user-data
|
||||
// to be sent by the driver.
|
||||
function void add_h_user_data(bit [HostDataWidth-1:0] data);
|
||||
h_user_data_q.push_back(data);
|
||||
endfunction
|
||||
|
||||
// Setter method for the user data queues - must be called externally to place specific user-data
|
||||
// to be sent by the driver.
|
||||
function void add_d_user_data(bit [DeviceDataWidth-1:0] data);
|
||||
d_user_data_q.push_back(data);
|
||||
endfunction
|
||||
|
||||
// Clear method for the user data queues - must be called externally to clear user-data queue
|
||||
// which was being set by add_h_user_data method.
|
||||
function void clear_h_user_data();
|
||||
h_user_data_q.delete();
|
||||
endfunction
|
||||
|
||||
// Clear method for the user data queues - must be called externally to clear user-data queue
|
||||
// which was being set by add_d_user_data method.
|
||||
function void clear_d_user_data();
|
||||
d_user_data_q.delete();
|
||||
endfunction
|
||||
|
||||
// Getter method for the user data queues - returns the first data entry.
|
||||
function bit [HostDataWidth-1:0] get_h_user_data();
|
||||
`DV_CHECK_NE_FATAL(has_h_user_data(), 0, "h_user_data_q is empty!")
|
||||
return h_user_data_q.pop_front();
|
||||
endfunction
|
||||
|
||||
// Getter method for the user data queues - returns the first data entry.
|
||||
function bit [DeviceDataWidth-1:0] get_d_user_data();
|
||||
`DV_CHECK_NE_FATAL(has_d_user_data(), 0, "d_user_data_q is empty!")
|
||||
return d_user_data_q.pop_front();
|
||||
endfunction
|
||||
|
||||
// Getter method for the user data queues - must be called externally to check whether there is
|
||||
// any user data in the queues.
|
||||
function bit has_h_user_data();
|
||||
return (h_user_data_q.size() > 0);
|
||||
endfunction
|
||||
|
||||
// Getter method for the user data queues - must be called externally to check whether there is
|
||||
// any user data in the queues.
|
||||
function bit has_d_user_data();
|
||||
return (d_user_data_q.size() > 0);
|
||||
endfunction
|
||||
|
||||
`uvm_object_param_utils_begin(push_pull_agent_cfg#(HostDataWidth, DeviceDataWidth))
|
||||
`uvm_field_enum(push_pull_agent_e, agent_type, UVM_DEFAULT)
|
||||
`uvm_field_enum(pull_handshake_e, pull_handshake_type, UVM_DEFAULT)
|
||||
`uvm_field_int(in_bidirectional_mode, UVM_DEFAULT)
|
||||
`uvm_field_int(host_delay_min, UVM_DEFAULT)
|
||||
`uvm_field_int(host_delay_max, UVM_DEFAULT)
|
||||
`uvm_field_int(device_delay_min, UVM_DEFAULT)
|
||||
`uvm_field_int(device_delay_max, UVM_DEFAULT)
|
||||
`uvm_field_int(req_lo_delay_min, UVM_DEFAULT)
|
||||
`uvm_field_int(req_lo_delay_max, UVM_DEFAULT)
|
||||
`uvm_field_int(ack_lo_delay_min, UVM_DEFAULT)
|
||||
`uvm_field_int(ack_lo_delay_max, UVM_DEFAULT)
|
||||
`uvm_field_int(zero_delays, UVM_DEFAULT)
|
||||
`uvm_field_int(start_default_device_seq, UVM_DEFAULT)
|
||||
`uvm_field_queue_int(h_user_data_q, UVM_DEFAULT)
|
||||
`uvm_field_queue_int(d_user_data_q, UVM_DEFAULT)
|
||||
`uvm_object_utils_end
|
||||
|
||||
`uvm_object_new
|
||||
|
||||
endclass
|
23
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent_cov.sv
vendored
Normal file
23
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent_cov.sv
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class push_pull_agent_cov #(parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth)
|
||||
extends dv_base_agent_cov #(
|
||||
push_pull_agent_cfg#(HostDataWidth, DeviceDataWidth)
|
||||
);
|
||||
|
||||
`uvm_component_param_utils(push_pull_agent_cov#(HostDataWidth, DeviceDataWidth))
|
||||
|
||||
// the base class provides the following handles for use:
|
||||
// push_pull_agent_cfg: cfg
|
||||
|
||||
// covergroups
|
||||
|
||||
function new(string name, uvm_component parent);
|
||||
super.new(name, parent);
|
||||
// instantiate all covergroups here
|
||||
endfunction : new
|
||||
|
||||
endclass
|
56
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent_pkg.sv
vendored
Normal file
56
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_agent_pkg.sv
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package push_pull_agent_pkg;
|
||||
// dep packages
|
||||
import uvm_pkg::*;
|
||||
import dv_utils_pkg::*;
|
||||
import dv_lib_pkg::*;
|
||||
|
||||
// macro includes
|
||||
`include "uvm_macros.svh"
|
||||
`include "dv_macros.svh"
|
||||
|
||||
// Instantiated in agent's config object.
|
||||
typedef enum {
|
||||
PushAgent,
|
||||
PullAgent
|
||||
} push_pull_agent_e;
|
||||
|
||||
// Pull req-ack handshake type.
|
||||
typedef enum {
|
||||
/*
|
||||
* The two-phase handshake follows this protocol:
|
||||
* ____________________
|
||||
* req _______/ \____________
|
||||
* ____
|
||||
* ack _______________________/ \____________
|
||||
*
|
||||
* Ack asserts for 1 cycle. Req is accepted when both req and ack is true.
|
||||
*/
|
||||
TwoPhase,
|
||||
|
||||
/*
|
||||
* The four-phase handshake follows this protocol:
|
||||
* __________________
|
||||
* req _______/ \______________
|
||||
* _______________________
|
||||
* ack _____________/ \___
|
||||
*
|
||||
* Req de-asserts after ack asserts. Ack de-asserts after the req
|
||||
* de-asserts. This type of handshake is more common in async domains.
|
||||
*/
|
||||
FourPhase
|
||||
} pull_handshake_e;
|
||||
|
||||
`include "push_pull_item.sv"
|
||||
`include "push_pull_agent_cfg.sv"
|
||||
`include "push_pull_agent_cov.sv"
|
||||
`include "push_pull_driver_lib.sv"
|
||||
`include "push_pull_monitor.sv"
|
||||
`include "push_pull_sequencer.sv"
|
||||
`include "push_pull_seq_list.sv"
|
||||
`include "push_pull_agent.sv"
|
||||
|
||||
endpackage : push_pull_agent_pkg
|
261
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_driver_lib.sv
vendored
Normal file
261
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_driver_lib.sv
vendored
Normal file
|
@ -0,0 +1,261 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
typedef class push_pull_sub_driver;
|
||||
typedef class push_host_driver;
|
||||
typedef class pull_host_driver;
|
||||
typedef class push_device_driver;
|
||||
typedef class pull_device_driver;
|
||||
|
||||
// 'Main' driver class that is created by the agent in active mode.
|
||||
//
|
||||
// The actual driving of signals is done by the 'sub' driver class which is virtualized. The correct
|
||||
// flavor of the sub driver is picked up base on whether it is a push / pull and whether its host or
|
||||
// device.
|
||||
class push_pull_driver #(
|
||||
parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth
|
||||
) extends dv_base_driver #(
|
||||
.ITEM_T(push_pull_item #(HostDataWidth, DeviceDataWidth)),
|
||||
.CFG_T (push_pull_agent_cfg #(HostDataWidth, DeviceDataWidth))
|
||||
);
|
||||
|
||||
push_pull_sub_driver #(HostDataWidth, DeviceDataWidth) sub_driver;
|
||||
|
||||
`uvm_component_param_utils(push_pull_driver#(HostDataWidth, DeviceDataWidth))
|
||||
`uvm_component_new
|
||||
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
|
||||
case ({cfg.if_mode, cfg.agent_type})
|
||||
{dv_utils_pkg::Host, PushAgent}: begin
|
||||
sub_driver = push_host_driver#(HostDataWidth, DeviceDataWidth)::type_id::create(
|
||||
"sub_driver");
|
||||
end
|
||||
{dv_utils_pkg::Host, PullAgent}: begin
|
||||
sub_driver = pull_host_driver#(HostDataWidth, DeviceDataWidth)::type_id::create(
|
||||
"sub_driver");
|
||||
end
|
||||
{dv_utils_pkg::Device, PushAgent}: begin
|
||||
sub_driver = push_device_driver#(HostDataWidth, DeviceDataWidth)::type_id::create(
|
||||
"sub_driver");
|
||||
end
|
||||
{dv_utils_pkg::Device, PullAgent}: begin
|
||||
sub_driver = pull_device_driver#(HostDataWidth, DeviceDataWidth)::type_id::create(
|
||||
"sub_driver");
|
||||
end
|
||||
default:;
|
||||
endcase
|
||||
sub_driver.cfg = cfg;
|
||||
endfunction
|
||||
|
||||
virtual task reset_signals();
|
||||
sub_driver.reset_signals();
|
||||
forever begin
|
||||
@(negedge cfg.vif.rst_n);
|
||||
`uvm_info(`gfn, "Driver is under reset", UVM_HIGH)
|
||||
sub_driver.reset_signals();
|
||||
@(posedge cfg.vif.rst_n);
|
||||
`uvm_info(`gfn, "Driver is out of reset", UVM_HIGH)
|
||||
end
|
||||
endtask
|
||||
|
||||
// Drive trans received from sequencer.
|
||||
virtual task get_and_drive();
|
||||
forever begin
|
||||
seq_item_port.try_next_item(req);
|
||||
if (req == null) begin
|
||||
sub_driver.wait_cb();
|
||||
continue;
|
||||
end
|
||||
|
||||
`uvm_info(`gfn, $sformatf("Driver received item:\n%0s", req.convert2string()), UVM_HIGH)
|
||||
sub_driver.drive_item(req);
|
||||
seq_item_port.item_done(req);
|
||||
end
|
||||
endtask
|
||||
|
||||
endclass
|
||||
|
||||
// Virtual 'sub' driver class.
|
||||
//
|
||||
// Extended to provide different push / pull / host / device mode flavors.
|
||||
virtual class push_pull_sub_driver #(
|
||||
parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth
|
||||
) extends uvm_object;
|
||||
|
||||
// The handle to the agent cfg object set by the main driver.
|
||||
push_pull_agent_cfg #(HostDataWidth, DeviceDataWidth) cfg;
|
||||
|
||||
`uvm_object_new
|
||||
|
||||
// Reset the interface signals driven to the DUT.
|
||||
pure virtual function void reset_signals();
|
||||
|
||||
// Wait for clock edges using the appropriate clocking block.
|
||||
pure virtual task wait_cb(int num = 1);
|
||||
|
||||
// Apply the item to the interface.
|
||||
pure virtual task drive_item(push_pull_item#(HostDataWidth, DeviceDataWidth) req);
|
||||
|
||||
endclass
|
||||
|
||||
// Push driver in host mode.
|
||||
class push_host_driver #(
|
||||
parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth
|
||||
) extends push_pull_sub_driver #(HostDataWidth, DeviceDataWidth);
|
||||
|
||||
`uvm_object_param_utils(push_host_driver#(HostDataWidth, DeviceDataWidth))
|
||||
`uvm_object_new
|
||||
|
||||
`define CB cfg.vif.host_push_cb
|
||||
|
||||
virtual function void reset_signals();
|
||||
cfg.vif.valid_int <= '0;
|
||||
cfg.vif.h_data_int <= 'x;
|
||||
endfunction
|
||||
|
||||
virtual task wait_cb(int num = 1);
|
||||
repeat (num) @(`CB);
|
||||
endtask
|
||||
|
||||
// Drives host side of ready/valid protocol
|
||||
virtual task drive_item(push_pull_item#(HostDataWidth, DeviceDataWidth) req);
|
||||
`DV_SPINWAIT_EXIT(
|
||||
repeat (req.host_delay) @(`CB);
|
||||
`CB.valid_int <= 1'b1;
|
||||
`CB.h_data_int <= req.h_data;
|
||||
do @(`CB); while (!`CB.ready);
|
||||
`CB.valid_int <= 1'b0;
|
||||
if (!cfg.hold_h_data_until_next_req) `CB.h_data_int <= 'x;,
|
||||
wait (cfg.in_reset);)
|
||||
endtask
|
||||
|
||||
`undef CB
|
||||
|
||||
endclass
|
||||
|
||||
// Pull driver in host mode.
|
||||
class pull_host_driver #(
|
||||
parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth
|
||||
) extends push_pull_sub_driver #(HostDataWidth, DeviceDataWidth);
|
||||
|
||||
`uvm_object_param_utils(pull_host_driver#(HostDataWidth, DeviceDataWidth))
|
||||
`uvm_object_new
|
||||
|
||||
`define CB cfg.vif.host_pull_cb
|
||||
|
||||
virtual function void reset_signals();
|
||||
cfg.vif.req_int <= '0;
|
||||
cfg.vif.h_data_int <= 'x;
|
||||
endfunction
|
||||
|
||||
virtual task wait_cb(int num = 1);
|
||||
repeat (num) @(`CB);
|
||||
endtask
|
||||
|
||||
// Drives host side of req/ack protocol
|
||||
virtual task drive_item(push_pull_item#(HostDataWidth, DeviceDataWidth) req);
|
||||
`DV_SPINWAIT_EXIT(
|
||||
repeat (req.host_delay) @(`CB);
|
||||
`CB.req_int <= 1'b1;
|
||||
`CB.h_data_int <= req.h_data;
|
||||
do @(`CB); while (!`CB.ack);
|
||||
if (cfg.pull_handshake_type == FourPhase) begin
|
||||
repeat (req.req_lo_delay) @(`CB);
|
||||
`CB.req_int <= 1'b0;
|
||||
do @(`CB); while (`CB.ack);
|
||||
end else begin
|
||||
`CB.req_int <= 1'b0;
|
||||
end
|
||||
if (!cfg.hold_h_data_until_next_req) `CB.h_data_int <= 'x;,
|
||||
wait (cfg.in_reset);)
|
||||
endtask
|
||||
|
||||
`undef CB
|
||||
|
||||
endclass
|
||||
|
||||
// Push driver in device mode.
|
||||
class push_device_driver #(
|
||||
parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth
|
||||
) extends push_pull_sub_driver #(HostDataWidth, DeviceDataWidth);
|
||||
|
||||
`uvm_object_param_utils(push_device_driver#(HostDataWidth, DeviceDataWidth))
|
||||
`uvm_object_new
|
||||
|
||||
`define CB cfg.vif.device_push_cb
|
||||
|
||||
virtual function void reset_signals();
|
||||
cfg.vif.ready_int <= '0;
|
||||
cfg.vif.d_data_int <= 'x;
|
||||
endfunction
|
||||
|
||||
virtual task wait_cb(int num = 1);
|
||||
repeat (num) @(`CB);
|
||||
endtask
|
||||
|
||||
// Drives device side of ready/valid protocol
|
||||
virtual task drive_item(push_pull_item#(HostDataWidth, DeviceDataWidth) req);
|
||||
`DV_SPINWAIT_EXIT(
|
||||
// TODO: this may be needed in future: while (!`CB.valid) @(`CB);
|
||||
repeat (req.device_delay) @(`CB);
|
||||
`CB.ready_int <= 1'b1;
|
||||
`CB.d_data_int <= req.d_data;
|
||||
@(`CB);
|
||||
`CB.ready_int <= 1'b0;
|
||||
if (!cfg.hold_d_data_until_next_req) `CB.d_data_int <= 'x;,
|
||||
wait (cfg.in_reset);)
|
||||
endtask
|
||||
|
||||
`undef CB
|
||||
|
||||
endclass
|
||||
|
||||
// Pull driver in device mode.
|
||||
class pull_device_driver #(
|
||||
parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth
|
||||
) extends push_pull_sub_driver #(HostDataWidth, DeviceDataWidth);
|
||||
|
||||
`uvm_object_param_utils(pull_device_driver#(HostDataWidth, DeviceDataWidth))
|
||||
`uvm_object_new
|
||||
|
||||
`define CB cfg.vif.device_pull_cb
|
||||
|
||||
virtual function void reset_signals();
|
||||
cfg.vif.ack_int <= '0;
|
||||
cfg.vif.d_data_int <= 'x;
|
||||
endfunction
|
||||
|
||||
virtual task wait_cb(int num = 1);
|
||||
repeat (num) @(`CB);
|
||||
endtask
|
||||
|
||||
// Drives device side of req/ack protocol
|
||||
virtual task drive_item(push_pull_item#(HostDataWidth, DeviceDataWidth) req);
|
||||
`DV_SPINWAIT_EXIT(
|
||||
while (!`CB.req) @(`CB);
|
||||
repeat (req.device_delay) @(`CB);
|
||||
`CB.ack_int <= 1'b1;
|
||||
`CB.d_data_int <= req.d_data;
|
||||
if (cfg.pull_handshake_type == FourPhase) begin
|
||||
do @(`CB); while (`CB.req);
|
||||
repeat (req.ack_lo_delay) @(`CB);
|
||||
end else begin
|
||||
@(`CB);
|
||||
end
|
||||
`CB.ack_int <= 1'b0;
|
||||
if (!cfg.hold_d_data_until_next_req) `CB.d_data_int <= 'x;,
|
||||
wait (cfg.in_reset);)
|
||||
endtask
|
||||
|
||||
`undef CB
|
||||
|
||||
endclass
|
175
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_if.sv
vendored
Normal file
175
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_if.sv
vendored
Normal file
|
@ -0,0 +1,175 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
`include "prim_assert.sv"
|
||||
|
||||
interface push_pull_if #(parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth) (
|
||||
input wire clk, input wire rst_n
|
||||
);
|
||||
|
||||
// Pins for the push handshake (ready/valid)
|
||||
wire ready;
|
||||
wire valid;
|
||||
|
||||
// Pins for the pull handshake (req/ack)
|
||||
wire req;
|
||||
wire ack;
|
||||
|
||||
// Parameterized width data payloads in both directions of the handshake.
|
||||
// Data sent from host to device
|
||||
wire [HostDataWidth-1:0] h_data;
|
||||
// Data sent from device to host
|
||||
wire [DeviceDataWidth-1:0] d_data;
|
||||
|
||||
// Internal versions of the interface output signals.
|
||||
// These signals are assigned as outputs depending on
|
||||
// how the agent is configured.
|
||||
logic ready_int;
|
||||
logic valid_int;
|
||||
logic req_int;
|
||||
logic ack_int;
|
||||
logic [HostDataWidth-1:0] h_data_int;
|
||||
logic [DeviceDataWidth-1:0] d_data_int;
|
||||
|
||||
// Interface mode - Host or Device
|
||||
dv_utils_pkg::if_mode_e if_mode;
|
||||
|
||||
// This bit controls what protocol assertions will be enabled,
|
||||
// e.g. if the agent is configured in Push mode, we do not want to
|
||||
// enable assertions relating to the Pull protocol.
|
||||
//
|
||||
// This bit is set to the appropriate value in push_pull_agent::build_phase().
|
||||
bit is_push_agent;
|
||||
|
||||
// This bit controls whether the agent is in bidirectional mode,
|
||||
// transferring data on both sides of the handshake.
|
||||
bit in_bidirectional_mode;
|
||||
|
||||
// Indicates whether pull interface follows 2-phase (0) or 4-phase (1) handshake.
|
||||
bit is_pull_handshake_4_phase;
|
||||
|
||||
// clocking blocks
|
||||
clocking host_push_cb @(posedge clk);
|
||||
input ready;
|
||||
input d_data;
|
||||
output valid_int;
|
||||
output h_data_int;
|
||||
endclocking
|
||||
|
||||
clocking device_push_cb @(posedge clk);
|
||||
output ready_int;
|
||||
output d_data_int;
|
||||
input valid;
|
||||
input h_data;
|
||||
endclocking
|
||||
|
||||
clocking host_pull_cb @(posedge clk);
|
||||
output req_int;
|
||||
output h_data_int;
|
||||
input ack;
|
||||
input d_data;
|
||||
endclocking
|
||||
|
||||
clocking device_pull_cb @(posedge clk);
|
||||
input req;
|
||||
input h_data;
|
||||
output ack_int;
|
||||
output d_data_int;
|
||||
endclocking
|
||||
|
||||
clocking mon_cb @(posedge clk);
|
||||
input ready;
|
||||
input valid;
|
||||
input req;
|
||||
input ack;
|
||||
input d_data;
|
||||
input h_data;
|
||||
endclocking
|
||||
|
||||
// Push output assignments
|
||||
assign ready = (is_push_agent && if_mode == dv_utils_pkg::Device) ? ready_int : 'z;
|
||||
assign valid = (is_push_agent && if_mode == dv_utils_pkg::Host) ? valid_int : 'z;
|
||||
|
||||
// Pull output assignments
|
||||
assign req = (!is_push_agent && if_mode == dv_utils_pkg::Host) ? req_int : 'z;
|
||||
assign ack = (!is_push_agent && if_mode == dv_utils_pkg::Device) ? ack_int : 'z;
|
||||
|
||||
// Data signal assignments
|
||||
assign h_data = (if_mode == dv_utils_pkg::Host) ? h_data_int : 'z;
|
||||
assign d_data = (if_mode == dv_utils_pkg::Device) ? d_data_int : 'z;
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Assertions for ready/valid protocol //
|
||||
/////////////////////////////////////////
|
||||
|
||||
// The ready and valid signals should always have known values.
|
||||
`ASSERT_KNOWN_IF(ReadyIsKnown_A, ready, is_push_agent, clk, !rst_n)
|
||||
`ASSERT_KNOWN_IF(ValidIsKnown_A, valid, is_push_agent, clk, !rst_n)
|
||||
|
||||
// Whenever valid is asserted, h_data must have a known value.
|
||||
`ASSERT_KNOWN_IF(H_DataKnownWhenValid_A, h_data, valid && is_push_agent, clk, !rst_n)
|
||||
|
||||
// Whenver ready is asserted and the agent is in bidirectional mode,
|
||||
// d_data must have a known value.
|
||||
`ASSERT_KNOWN_IF(D_DataKnownWhenReady_A, d_data,
|
||||
ready && is_push_agent && in_bidirectional_mode, clk, !rst_n)
|
||||
|
||||
// When valid is asserted but ready is low the h_data must stay stable.
|
||||
`ASSERT_IF(H_DataStableWhenValidAndNotReady_A, (valid && !ready) |=> $stable(h_data),
|
||||
is_push_agent, clk, !rst_n)
|
||||
|
||||
// When valid is asserted, it must stay high until seeing ready be asserted.
|
||||
`ASSERT_IF(ValidHighUntilReady_A, $rose(valid) |-> (valid throughout ready [->1]),
|
||||
is_push_agent, clk, !rst_n)
|
||||
|
||||
/////////////////////////////////////
|
||||
// Assertions for req/ack protocol //
|
||||
/////////////////////////////////////
|
||||
|
||||
// The req and ack signals should always have known values.
|
||||
`ASSERT_KNOWN_IF(ReqIsKnown_A, req, !is_push_agent, clk, !rst_n)
|
||||
`ASSERT_KNOWN_IF(AckIsKnown_A, ack, !is_push_agent, clk, !rst_n)
|
||||
|
||||
// When ack is asserted, d_data must have a known value.
|
||||
`ASSERT_KNOWN_IF(D_DataKnownWhenAck_A, d_data, ack && !is_push_agent, clk, !rst_n)
|
||||
|
||||
// When req is asserted and the agent is in bidirectional mode,
|
||||
// h_data must have a known value.
|
||||
`ASSERT_KNOWN_IF(H_DataKnownWhenReq_A, h_data,
|
||||
req && !is_push_agent && in_bidirectional_mode, clk, !rst_n)
|
||||
|
||||
// When req is asserted but ack is low, and the agent is in bidirectional mode,
|
||||
// h_data must remain stable.
|
||||
`ASSERT_IF(H_DataStableWhenBidirectionalAndReq_A, (req && !ack) |=> $stable(h_data),
|
||||
!is_push_agent && in_bidirectional_mode, clk, !rst_n)
|
||||
|
||||
// TODO: The following two assertions make a rather important assumption about the req/ack
|
||||
// protocol that will be used for the key/csrng interfaces, which is that no requests
|
||||
// are allowed to be dropped by the network. This issue is made more complex by the
|
||||
// fact that several of the IPs connected to this network may be in different clock
|
||||
// domains, requiring CDC.
|
||||
// Based on the final decision on this issue, these assertions may have to be removed
|
||||
// if it is allowed for requests to be dropped.
|
||||
|
||||
// I 2-phase req-ack handshake, ack cannot be 1 if req is not 1.
|
||||
`ASSERT_IF(AckAssertedOnlyWhenReqAsserted_A, ack |-> req,
|
||||
!is_push_agent && !is_pull_handshake_4_phase, clk, !rst_n)
|
||||
|
||||
// Req is asserted only after previous ack is de-asserted.
|
||||
`ASSERT_IF(NoAckOnNewReq_A, $rose(req) |-> !($past(ack, 1)) && !ack,
|
||||
!is_push_agent, clk, !rst_n)
|
||||
|
||||
// When req is asserted, it must stay high until a corresponding ack is seen.
|
||||
`ASSERT_IF(ReqHighUntilAck_A, $rose(req) |-> (req throughout ack[->1]),
|
||||
!is_push_agent, clk, !rst_n)
|
||||
|
||||
// When ack is asserted, it must stay high until a corresponding req is de-asserted,
|
||||
// in case of four-phase handshake.
|
||||
`ASSERT_IF(AckHighUntilReq_A, $rose(ack) |-> (ack throughout (!req[->1])),
|
||||
!is_push_agent && is_pull_handshake_4_phase, clk, !rst_n)
|
||||
|
||||
// TODO: Add support for async clock domains.
|
||||
|
||||
endinterface
|
56
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_item.sv
vendored
Normal file
56
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_item.sv
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class push_pull_item #(parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth)
|
||||
extends uvm_sequence_item;
|
||||
|
||||
rand bit [HostDataWidth-1:0] h_data;
|
||||
rand bit [DeviceDataWidth-1:0] d_data;
|
||||
|
||||
// Host-side delay for both push/pull protocols.
|
||||
rand int unsigned host_delay;
|
||||
constraint host_delay_max_c {
|
||||
soft host_delay <= 1000;
|
||||
}
|
||||
|
||||
// Device-side delay for both push/pull protocols.
|
||||
rand int unsigned device_delay;
|
||||
constraint device_delay_max_c {
|
||||
soft device_delay <= 1000;
|
||||
}
|
||||
|
||||
// 4-phase pull protocol delays to de-assert req. This delay is applied after ack assertion.
|
||||
rand int unsigned req_lo_delay;
|
||||
constraint req_lo_delay_max_c {
|
||||
soft req_lo_delay <= 1000;
|
||||
}
|
||||
|
||||
// 4-phase pull protocol delays to de-assert ack. This delay is applied after req de-assertion.
|
||||
rand int unsigned ack_lo_delay;
|
||||
constraint ack_lo_delay_max_c {
|
||||
soft ack_lo_delay <= 1000;
|
||||
}
|
||||
|
||||
`uvm_object_param_utils_begin(push_pull_item#(HostDataWidth, DeviceDataWidth))
|
||||
`uvm_field_int(h_data, UVM_DEFAULT)
|
||||
`uvm_field_int(d_data, UVM_DEFAULT)
|
||||
`uvm_field_int(host_delay, UVM_DEFAULT)
|
||||
`uvm_field_int(device_delay, UVM_DEFAULT)
|
||||
`uvm_field_int(req_lo_delay, UVM_DEFAULT)
|
||||
`uvm_field_int(ack_lo_delay, UVM_DEFAULT)
|
||||
`uvm_object_utils_end
|
||||
|
||||
`uvm_object_new
|
||||
|
||||
virtual function string convert2string();
|
||||
return {$sformatf("h_data = 0x%0x ", h_data),
|
||||
$sformatf("d_data = 0x%0x ", d_data),
|
||||
$sformatf("host_delay = 0x%0d ", host_delay),
|
||||
$sformatf("device_delay = 0x%0d ", device_delay),
|
||||
$sformatf("req_lo_delay = 0x%0d ", req_lo_delay),
|
||||
$sformatf("ack_lo_delay = 0x%0d ", ack_lo_delay)};
|
||||
endfunction
|
||||
|
||||
endclass
|
143
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_monitor.sv
vendored
Normal file
143
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_monitor.sv
vendored
Normal file
|
@ -0,0 +1,143 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class push_pull_monitor #(parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth)
|
||||
extends dv_base_monitor #(
|
||||
.ITEM_T (push_pull_item#(HostDataWidth, DeviceDataWidth)),
|
||||
.CFG_T (push_pull_agent_cfg#(HostDataWidth, DeviceDataWidth)),
|
||||
.COV_T (push_pull_agent_cov#(HostDataWidth, DeviceDataWidth))
|
||||
);
|
||||
`uvm_component_param_utils(push_pull_monitor#(HostDataWidth, DeviceDataWidth))
|
||||
|
||||
// the base class provides the following handles for use:
|
||||
// push_pull_agent_cfg: cfg
|
||||
// push_pull_agent_cov: cov
|
||||
// uvm_analysis_port #(ITEM_T): analysis_port
|
||||
// uvm_analysis_port #(ITEM_T): req_analysis_port;
|
||||
|
||||
`uvm_component_new
|
||||
|
||||
task run_phase(uvm_phase phase);
|
||||
@(posedge cfg.vif.rst_n);
|
||||
fork
|
||||
monitor_reset();
|
||||
collect_trans(phase);
|
||||
// Collect partial pull reqs for the reactive pull device agent.
|
||||
collect_pull_req();
|
||||
join_none
|
||||
endtask
|
||||
|
||||
virtual protected task monitor_reset();
|
||||
forever begin
|
||||
@(negedge cfg.vif.rst_n);
|
||||
cfg.in_reset = 1;
|
||||
@(posedge cfg.vif.rst_n);
|
||||
cfg.in_reset = 0;
|
||||
end
|
||||
endtask
|
||||
|
||||
// Shorthand for restarting forever loop on reset detection.
|
||||
`define WAIT_FOR_RESET \
|
||||
if (cfg.in_reset) begin \
|
||||
wait (!cfg.in_reset); \
|
||||
continue; \
|
||||
end
|
||||
|
||||
// Collect fully-completed transactions.
|
||||
//
|
||||
// TODO : sample covergroups
|
||||
virtual protected task collect_trans(uvm_phase phase);
|
||||
if (cfg.agent_type == PushAgent) begin
|
||||
forever begin
|
||||
@(cfg.vif.mon_cb);
|
||||
`WAIT_FOR_RESET
|
||||
if (cfg.vif.mon_cb.ready && cfg.vif.mon_cb.valid) begin
|
||||
create_and_write_item();
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
forever begin
|
||||
@(cfg.vif.mon_cb);
|
||||
`WAIT_FOR_RESET
|
||||
if (cfg.vif.mon_cb.req && cfg.vif.mon_cb.ack) begin
|
||||
create_and_write_item();
|
||||
// Wait for req to de-assert in case of four-phase handshake.
|
||||
if (cfg.pull_handshake_type == FourPhase) begin
|
||||
`uvm_info(`gfn, "Waiting for 4-phase req-ack to de-asssert", UVM_HIGH)
|
||||
`DV_SPINWAIT_EXIT(while (cfg.vif.mon_cb.ack) @(cfg.vif.mon_cb);,
|
||||
wait (cfg.in_reset))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
// Collects partial pull requests.
|
||||
//
|
||||
// This task is only used for device agents using the Pull protocol.
|
||||
// It will pick up any incoming requests from the DUT and send a signal to the
|
||||
// sequencer (in the form of a sequence item), which will then be forwarded to
|
||||
// the sequence, which then generates the appropriate response item.
|
||||
//
|
||||
// TODO: This assumes requests cannot be dropped, and might need to be fixed
|
||||
// if this is allowed.
|
||||
virtual protected task collect_pull_req();
|
||||
push_pull_item#(HostDataWidth, DeviceDataWidth) item;
|
||||
|
||||
if (!(cfg.agent_type == PullAgent && cfg.if_mode == dv_utils_pkg::Device)) return;
|
||||
forever begin
|
||||
@(cfg.vif.mon_cb);
|
||||
`WAIT_FOR_RESET
|
||||
if (cfg.vif.mon_cb.req) begin
|
||||
`uvm_info(`gfn, $sformatf("[%0s] pull req detected", cfg.agent_type), UVM_HIGH)
|
||||
// TODO: sample any covergroups
|
||||
item = push_pull_item#(HostDataWidth, DeviceDataWidth)::type_id::create("item");
|
||||
item.h_data = cfg.vif.mon_cb.h_data;
|
||||
req_analysis_port.write(item);
|
||||
// After picking up a request, wait until a response is sent before
|
||||
// detecting another request, as this is not a pipelined protocol.
|
||||
`DV_SPINWAIT_EXIT(while (!cfg.vif.mon_cb.ack) @(cfg.vif.mon_cb);,
|
||||
wait (cfg.in_reset))
|
||||
if (cfg.pull_handshake_type == FourPhase) begin
|
||||
`DV_SPINWAIT_EXIT(while (cfg.vif.mon_cb.ack) @(cfg.vif.mon_cb);,
|
||||
wait (cfg.in_reset))
|
||||
end
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
`undef WAIT_FOR_RESET
|
||||
|
||||
// Creates and writes the item to the analysis_port.
|
||||
//
|
||||
// The onus is on the caller to invoke this function at the right time -
|
||||
// i.e. when the transaction is valid.
|
||||
virtual protected function void create_and_write_item();
|
||||
push_pull_item#(HostDataWidth, DeviceDataWidth) item;
|
||||
item = push_pull_item#(HostDataWidth, DeviceDataWidth)::type_id::create("item");
|
||||
item.d_data = cfg.vif.mon_cb.d_data;
|
||||
item.h_data = cfg.vif.mon_cb.h_data;
|
||||
`uvm_info(`gfn,
|
||||
$sformatf("[%0s] transaction detected: h_data[0x%0x], d_data[0x%0x]",
|
||||
cfg.agent_type, item.h_data, item.d_data), UVM_HIGH)
|
||||
analysis_port.write(item);
|
||||
endfunction
|
||||
|
||||
// Detects periods of inactivity for the ok_to_end watchdog.
|
||||
//
|
||||
// Set ok_to_end bit to detect inactivity on the bus. Spawned by
|
||||
// dv_base_monitor as a thread towards the end of run_phase.
|
||||
virtual task monitor_ready_to_end();
|
||||
forever begin
|
||||
@(cfg.vif.mon_cb);
|
||||
if (cfg.agent_type == PushAgent) begin
|
||||
ok_to_end = !cfg.vif.mon_cb.valid;
|
||||
end else begin
|
||||
ok_to_end = !cfg.vif.mon_cb.req && !cfg.vif.mon_cb.ack;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
endclass
|
14
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_sequencer.sv
vendored
Normal file
14
vendor/lowrisc_ip/dv/sv/push_pull_agent/push_pull_sequencer.sv
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class push_pull_sequencer #(parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth)
|
||||
extends dv_base_sequencer #(
|
||||
.ITEM_T (push_pull_item#(HostDataWidth, DeviceDataWidth)),
|
||||
.CFG_T (push_pull_agent_cfg#(HostDataWidth, DeviceDataWidth))
|
||||
);
|
||||
`uvm_component_param_utils(push_pull_sequencer#(HostDataWidth, DeviceDataWidth))
|
||||
`uvm_component_new
|
||||
|
||||
endclass
|
39
vendor/lowrisc_ip/dv/sv/push_pull_agent/seq_lib/push_pull_base_seq.sv
vendored
Normal file
39
vendor/lowrisc_ip/dv/sv/push_pull_agent/seq_lib/push_pull_base_seq.sv
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
class push_pull_base_seq #(parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth)
|
||||
extends dv_base_seq #(
|
||||
.REQ (push_pull_item#(HostDataWidth, DeviceDataWidth)),
|
||||
.CFG_T (push_pull_agent_cfg#(HostDataWidth, DeviceDataWidth)),
|
||||
.SEQUENCER_T (push_pull_sequencer#(HostDataWidth, DeviceDataWidth))
|
||||
);
|
||||
`uvm_object_param_utils(push_pull_base_seq#(HostDataWidth, DeviceDataWidth))
|
||||
|
||||
`uvm_object_new
|
||||
|
||||
// Randomizes the req or response.
|
||||
//
|
||||
// Regardless of agent or item type, we can apply the same set of limits.
|
||||
virtual function void randomize_item(push_pull_item #(HostDataWidth, DeviceDataWidth) item);
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(item,
|
||||
if (cfg.zero_delays) {
|
||||
host_delay == 0;
|
||||
device_delay == 0;
|
||||
req_lo_delay == 0;
|
||||
ack_lo_delay == 0;
|
||||
} else {
|
||||
host_delay inside {[cfg.host_delay_min : cfg.host_delay_max]};
|
||||
device_delay inside {[cfg.device_delay_min : cfg.device_delay_max]};
|
||||
req_lo_delay inside {[cfg.req_lo_delay_min : cfg.req_lo_delay_max]};
|
||||
ack_lo_delay inside {[cfg.ack_lo_delay_min : cfg.ack_lo_delay_max]};
|
||||
}
|
||||
)
|
||||
endfunction
|
||||
|
||||
virtual task body();
|
||||
`uvm_fatal(`gtn, "Need to override this when you extend from this class!")
|
||||
endtask
|
||||
|
||||
endclass
|
75
vendor/lowrisc_ip/dv/sv/push_pull_agent/seq_lib/push_pull_device_seq.sv
vendored
Normal file
75
vendor/lowrisc_ip/dv/sv/push_pull_agent/seq_lib/push_pull_device_seq.sv
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Response sequence for Push and Pull protocols.
|
||||
// This sequence will infinitely pol for any DUT requests detected by
|
||||
// the monitor, and trigger the response driver anytime a request is detected.
|
||||
|
||||
class push_pull_device_seq #(parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth)
|
||||
extends push_pull_base_seq #(HostDataWidth, DeviceDataWidth);
|
||||
|
||||
`uvm_object_param_utils(push_pull_device_seq#(HostDataWidth, DeviceDataWidth))
|
||||
|
||||
`uvm_object_new
|
||||
|
||||
// Randomizes the device rsp.
|
||||
//
|
||||
// The randomization works out the same regardless of the agent type.
|
||||
virtual function void randomize_item(push_pull_item #(HostDataWidth, DeviceDataWidth) item);
|
||||
super.randomize_item(item);
|
||||
// If user-provided data is available, use it.
|
||||
if (cfg.has_d_user_data()) item.d_data = cfg.get_d_user_data();
|
||||
endfunction
|
||||
|
||||
virtual task body();
|
||||
if (cfg.agent_type == PushAgent) begin
|
||||
push_device_thread();
|
||||
end else begin
|
||||
pull_device_thread();
|
||||
end
|
||||
endtask
|
||||
|
||||
// Sends random rsps (assertion of ready) back to host.
|
||||
//
|
||||
// In Push mode, continuously send an empty but randomized sequence item
|
||||
// to the device driver (which just needs to assert ready).
|
||||
// If the agent is in bidirectional mode, send the corresponding data.
|
||||
// TODO: for bidirectional mode, there may be a need for the returned device data to be
|
||||
// constructed based on the received host data. This may need to be made "reactive" as well.
|
||||
virtual task push_device_thread();
|
||||
forever begin
|
||||
wait (!cfg.in_reset);
|
||||
`uvm_create(req)
|
||||
start_item(req);
|
||||
randomize_item(req);
|
||||
finish_item(req);
|
||||
get_response(rsp);
|
||||
end
|
||||
endtask
|
||||
|
||||
// Sends random rsps (device data and ack) back to host.
|
||||
virtual task pull_device_thread();
|
||||
push_pull_item #(HostDataWidth, DeviceDataWidth) req_q[$];
|
||||
fork
|
||||
forever begin : get_req
|
||||
p_sequencer.req_analysis_fifo.get(req);
|
||||
req_q.push_back(req);
|
||||
end : get_req
|
||||
forever begin : send_rsp
|
||||
if (cfg.in_reset) begin
|
||||
req_q.delete();
|
||||
wait (!cfg.in_reset);
|
||||
end
|
||||
wait (req_q.size());
|
||||
rsp = req_q.pop_front();
|
||||
start_item(rsp);
|
||||
randomize_item(rsp);
|
||||
finish_item(rsp);
|
||||
get_response(rsp);
|
||||
end : send_rsp
|
||||
join
|
||||
endtask
|
||||
|
||||
endclass
|
37
vendor/lowrisc_ip/dv/sv/push_pull_agent/seq_lib/push_pull_host_seq.sv
vendored
Normal file
37
vendor/lowrisc_ip/dv/sv/push_pull_agent/seq_lib/push_pull_host_seq.sv
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Request sequence for Push and Pull protocols.
|
||||
// This sequence will send num_trans requests to the DUT.
|
||||
|
||||
class push_pull_host_seq #(parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth)
|
||||
extends push_pull_base_seq #(HostDataWidth, DeviceDataWidth);
|
||||
|
||||
`uvm_object_param_utils(push_pull_host_seq#(HostDataWidth, DeviceDataWidth))
|
||||
|
||||
`uvm_object_new
|
||||
|
||||
// Default to send 1 transactions.
|
||||
// Can be overridden at a higher layer.
|
||||
int unsigned num_trans = 1;
|
||||
|
||||
// Randomizes the host req.
|
||||
virtual function void randomize_item(push_pull_item #(HostDataWidth, DeviceDataWidth) item);
|
||||
super.randomize_item(item);
|
||||
// If user-provided data is available, use it.
|
||||
if (cfg.has_h_user_data()) item.h_data = cfg.get_h_user_data();
|
||||
endfunction
|
||||
|
||||
virtual task body();
|
||||
repeat (num_trans) begin : send_req
|
||||
`uvm_create(req)
|
||||
start_item(req);
|
||||
randomize_item(req);
|
||||
finish_item(req);
|
||||
get_response(rsp);
|
||||
end : send_req
|
||||
endtask
|
||||
|
||||
endclass
|
58
vendor/lowrisc_ip/dv/sv/push_pull_agent/seq_lib/push_pull_indefinite_host_seq.sv
vendored
Normal file
58
vendor/lowrisc_ip/dv/sv/push_pull_agent/seq_lib/push_pull_indefinite_host_seq.sv
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Request sequence for Push and Pull protocols.
|
||||
//
|
||||
// Similiar push_pull_host_seq, this sequence will send an unlimited number of requests to
|
||||
// the DUT. It is the responsibility of the parent sequence to halt this sequence by setting
|
||||
// the stop field.
|
||||
//
|
||||
|
||||
class push_pull_indefinite_host_seq #(parameter int HostDataWidth = 32,
|
||||
parameter int DeviceDataWidth = HostDataWidth)
|
||||
extends push_pull_host_seq #(HostDataWidth, DeviceDataWidth);
|
||||
|
||||
`uvm_object_param_utils(push_pull_indefinite_host_seq#(HostDataWidth, DeviceDataWidth))
|
||||
|
||||
`uvm_object_new
|
||||
|
||||
typedef enum int {
|
||||
Continue = 0,
|
||||
Stop = 1,
|
||||
HardStop = 2
|
||||
} stop_status_e;
|
||||
|
||||
stop_status_e stop_status;
|
||||
|
||||
virtual task body();
|
||||
fork : isolation_fork
|
||||
begin
|
||||
fork
|
||||
begin
|
||||
wait(stop_status == HardStop);
|
||||
`uvm_info(`gfn, "Rec'd stop message", UVM_FULL)
|
||||
end
|
||||
while (stop_status == Continue) begin : send_req
|
||||
`uvm_create(req)
|
||||
start_item(req);
|
||||
randomize_item(req);
|
||||
finish_item(req);
|
||||
get_response(rsp);
|
||||
end : send_req
|
||||
join_any;
|
||||
disable fork;
|
||||
end
|
||||
join : isolation_fork
|
||||
`uvm_info(`gfn, "STOPPED", UVM_FULL)
|
||||
endtask
|
||||
|
||||
virtual task stop(bit hard = 1);
|
||||
stop_status = hard ? HardStop : Stop;
|
||||
endtask
|
||||
|
||||
virtual task pre_start();
|
||||
super.pre_start();
|
||||
stop_status = Continue;
|
||||
endtask
|
||||
endclass
|
8
vendor/lowrisc_ip/dv/sv/push_pull_agent/seq_lib/push_pull_seq_list.sv
vendored
Normal file
8
vendor/lowrisc_ip/dv/sv/push_pull_agent/seq_lib/push_pull_seq_list.sv
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
`include "push_pull_base_seq.sv"
|
||||
`include "push_pull_host_seq.sv"
|
||||
`include "push_pull_indefinite_host_seq.sv"
|
||||
`include "push_pull_device_seq.sv"
|
Loading…
Add table
Add a link
Reference in a new issue