Skip to content

Commit 69b9f76

Browse files
committed
[kmac,dv] Rewrite kmac_app_agent to be more general
This work adapts the agent to match the newly defined interface with minimal changes. This should allow OTBN to interact with KMAC through the interface in a more complicated way than existing users. The agent that was in place isn't really able to handle the tweaked protocol, so this commit rewrites it to allow extending things smoothly. Upsettingly, the commit is enormous! I couldn't figure out how to split it up into smaller pieces. :-( Important changes: - The agent gets split in two ("kmac_app_device_agent" and "kmac_app_host_agent"). These have different sequencers, corresponding to the fact that they fundamentally drive different sorts of items. - We no longer use push_pull_agent. It was already a slightly awkward fit (I think) and can't really support the new protocol. - kmac_app_device_driver now watches app requests and creates sequence items to represent these requests. They get broadcast through m_req_port. That port is connected to the sequencer's m_req_fifo, which can be consumed by the sequence that sends responses. - Sequence items are a bit more structured: + A request is sent in multiple beats, which each get a kmac_app_req_item where the last has m_last set. + The items representing the beats of a request are grouped into a "packet", represented by a kmac_app_req_packet_item. This contains a queue with the kmac_app_req_item objects for the beats. + A response is represented by a kmac_app_rsp_item. + The monitor sees complete transactions (a request followed by a response) and represents this as a kmac_app_mon_item, which contains a kmac_app_req_packet_item and a kmac_app_rsp_item. - The signals in kmac_app_if are now driven through clocking blocks in both directions, depending on an if_mode variable. - We don't use phase sequences any more. I think this is not really recommended and we can just start the "device responder" sequences from the test: probably a bit clearer. For example, see keymgr_base_test.sv (three lines of code). Minor ("while we're at it") changes: - The interface gets a more conventional "_if" name. - It also exposes the request and response as inout ports, which makes it a bit easier to use. See hw/ip/keymgr/dv/tb.sv for an example of the change. - Fixed dubious function names in kmac_app_agent_cfg: things that acted on a digest, composed of two shares, were previously called e.g. add_user_digest_share. But they acted on both shares! Drop the _share" part. - Any new or dramatically-altered classes use out-of-block definitions and I've added meaningful documentation comments to functions, tasks and class variables. - The imports in kmac_app_agent_pkg are a bit more precise (mainly because I was concentrating to make sure I got the right thing from the right place). - The StrbAlignLSB_A assertions in kmac_app_intf were more complicated than needed. Group them into a single assertion. Also, express the assertions with default clocking/disable to make them easier to understand. - Rather than using field macros for the new classes, I've defined do_print/do_copy manually. This is probably a bit more efficient at runtime and (more importantly) lets us be explicit about things like radixes. For example, kmac_app_req_item always uses hexadecimal for its m_data field. - Since the strobe line is always required to be contiguous and aligned to the lsb, kmac_app_req_item represents it as just the number of valid bytes (m_num_bytes). This makes some of the code deailing with the item a bit simpler. For example, see kmac_app_host_seq: handling partial words when cfg.inject_zero_in_host_strb is now rather less mysterious. - I've renamed kmac_app_rsp_item::get_is_kmac_rsp_data_invalid to just is_kmac_rsp_data_invalid. There's no need for the "double accessor name". - Since I was having to touch the code anyway, I've made the way scoreboards consume items from the agent a bit simpler. For example, keymgr_scoreboard now has two imp imports (for requests and transactions) and doesn't have to manually maintain fifos in the same way. - I renamed the agents that connect to KMAC in the keymgr and keymgr_dpe environments to just m_kmac_agent: there's not much point in cluttering the code with longer names. Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
1 parent e804155 commit 69b9f76

69 files changed

Lines changed: 1736 additions & 1091 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

hw/dv/sv/kmac_app_agent/kmac_app_agent.core

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,24 @@ filesets:
99
depend:
1010
- lowrisc:dv:dv_utils
1111
- lowrisc:dv:dv_lib
12-
- lowrisc:dv:push_pull_agent
1312
- lowrisc:ip:keymgr_pkg
1413
- lowrisc:ip:kmac_pkg
1514
files:
15+
- kmac_app_if.sv
1616
- kmac_app_agent_pkg.sv
17-
- kmac_app_intf.sv
18-
- kmac_app_item.sv: {is_include_file: true}
1917
- kmac_app_agent_cfg.sv: {is_include_file: true}
20-
- kmac_app_sequencer.sv: {is_include_file: true}
21-
- kmac_app_agent_cov.sv: {is_include_file: true}
22-
- kmac_app_driver.sv: {is_include_file: true}
23-
- kmac_app_host_driver.sv: {is_include_file: true}
18+
- kmac_app_device_agent.sv: {is_include_file: true}
2419
- kmac_app_device_driver.sv: {is_include_file: true}
20+
- kmac_app_device_sequencer.sv: {is_include_file: true}
21+
- kmac_app_host_agent.sv: {is_include_file: true}
22+
- kmac_app_host_driver.sv: {is_include_file: true}
2523
- kmac_app_monitor.sv: {is_include_file: true}
26-
- kmac_app_agent.sv: {is_include_file: true}
27-
- seq_lib/kmac_app_base_seq.sv: {is_include_file: true}
24+
- kmac_app_mon_item.sv: {is_include_file: true}
25+
- kmac_app_req_item.sv: {is_include_file: true}
26+
- kmac_app_req_packet_item.sv: {is_include_file: true}
27+
- kmac_app_rsp_item.sv: {is_include_file: true}
2828
- seq_lib/kmac_app_host_seq.sv: {is_include_file: true}
2929
- seq_lib/kmac_app_device_seq.sv: {is_include_file: true}
30-
- seq_lib/kmac_app_seq_list.sv: {is_include_file: true}
3130
file_type: systemVerilogSource
3231

3332
targets:

hw/dv/sv/kmac_app_agent/kmac_app_agent.sv

Lines changed: 0 additions & 74 deletions
This file was deleted.

hw/dv/sv/kmac_app_agent/kmac_app_agent_cfg.sv

Lines changed: 68 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,72 +2,98 @@
22
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
33
// SPDX-License-Identifier: Apache-2.0
44

5-
class kmac_app_agent_cfg extends dv_reactive_agent_cfg;
5+
class kmac_app_agent_cfg extends dv_base_agent_cfg;
6+
// Handle to the agent's interface
7+
virtual kmac_app_if vif;
68

7-
// interface handle used by driver, monitor & the sequencer, via cfg handle
8-
virtual kmac_app_intf vif;
9+
// Used in Device mode. The maximum length of time that the device is not ready when it is not
10+
// processing a request.
11+
int unsigned max_idle_time_not_ready = 8;
912

13+
// Used in Device mode. The percentage chance for the device to be ready to receive a request on a
14+
// cycle (assuming the device is idle and there haven't already been max_idle_time_not_ready
15+
// cycles of not being ready)
16+
int unsigned idle_ready_pct = 50;
17+
18+
// Bounds used by the host sequence for the m_delay value in the kmac_app_req_item objects it
19+
// generates. This is the number of cycles to wait before sending the request.
1020
int unsigned req_delay_min = 0;
11-
int unsigned req_delay_max = 100;
21+
int unsigned req_delay_max = 10;
1222

13-
// delay between last message request and first digest response
23+
// Bounds used by the device sequence for the number of cycles between when a request is accepted
24+
// and when a response is sent.
1425
int unsigned rsp_delay_min = 0;
1526
int unsigned rsp_delay_max = 100;
1627

17-
// Enables/disable all protocol delays.
28+
// If this is set then the device and response sequence will both constrain delays to be zero.
1829
rand bit zero_delays;
1930

20-
// Enable starting the device auto-response sequence by default if configured in Device mode.
21-
bit start_default_device_seq = 1;
22-
2331
// Knob to enable percentage of error response in auto-response sequence.
2432
int unsigned error_rsp_pct = 0;
2533

26-
// Knob to control whether an error response can be caused by all zeros or all ones in one of the
27-
// shares.
34+
// Knob to control whether a response where a share is '0 or '1 is considered an error response
2835
bit constant_share_means_error = 1'b1;
2936

3037
// Knob to allow injecting zeros in strb.
3138
bit inject_zero_in_host_strb = 0;
3239

33-
rand push_pull_agent_cfg#(`CONNECT_DATA_WIDTH) m_data_push_agent_cfg;
40+
// True if this app interface is capable of masking
41+
bit has_masking = 1;
3442

35-
// KMAC digest share0/1 that can be set from test env.
36-
kmac_pkg::rsp_digest_t rsp_digest_hs[$];
43+
// A queue of digest responses. If the agent is in Device mode, this can be filled by calling
44+
// add_user_digest. Once that has been done, the automatic device-mode sequence will respond the
45+
// data in this queue.
46+
rsp_digest_t rsp_digest_hs[$];
3747

38-
// Bias randomization in favor of enabling zero delays less often.
39-
constraint zero_delays_c {
40-
zero_delays dist { 0 := 8,
41-
1 := 2 };
42-
}
43-
44-
// Setter method for the user digest share queues - must be called externally to place specific user-digest_share0
45-
// to be sent by the driver.
46-
function void add_user_digest_share(kmac_pkg::rsp_digest_t rsp_digest_h);
47-
rsp_digest_hs.push_back(rsp_digest_h);
48-
endfunction
49-
// Getter method for the user digest share - returns the first data entry.
50-
function kmac_pkg::rsp_digest_t get_user_digest_share();
51-
`DV_CHECK_NE_FATAL(has_user_digest_share(), 0, "rsp_digest_share0 is empty!")
52-
return rsp_digest_hs.pop_front();
53-
endfunction
54-
// Getter method for the user digest share - must be called externally to check whether there is
55-
// any user data in the queues.
56-
function bit has_user_digest_share();
57-
return (rsp_digest_hs.size() > 0);
58-
endfunction
48+
extern function new (string name = "");
49+
50+
// Add a digest to the user digest queue.
51+
//
52+
// This only makes sense in Device mode.
53+
extern function void add_user_digest(rsp_digest_t rsp_digest_h);
54+
55+
// Pop the first item from the user digest queue. This will fail with an error if the queue is
56+
// empty.
57+
extern function rsp_digest_t pop_user_digest();
58+
59+
// Returns true if the user digest queue is nonempty
60+
extern function bit has_user_digest();
5961

6062
`uvm_object_utils_begin(kmac_app_agent_cfg)
63+
`uvm_field_int(req_delay_min, UVM_DEFAULT)
64+
`uvm_field_int(req_delay_max, UVM_DEFAULT)
6165
`uvm_field_int(rsp_delay_min, UVM_DEFAULT)
6266
`uvm_field_int(rsp_delay_max, UVM_DEFAULT)
6367
`uvm_field_int(zero_delays, UVM_DEFAULT)
64-
`uvm_field_int(start_default_device_seq, UVM_DEFAULT)
6568
`uvm_object_utils_end
6669

67-
function new (string name = "");
68-
super.new(name);
69-
m_data_push_agent_cfg = push_pull_agent_cfg#(`CONNECT_DATA_WIDTH)::type_id::create(
70-
"m_data_push_agent_cfg");
71-
endfunction : new
72-
70+
// Bias randomization in favor of enabling zero delays less often.
71+
extern constraint zero_delays_c;
7372
endclass
73+
74+
function kmac_app_agent_cfg::new (string name = "");
75+
super.new(name);
76+
endfunction : new
77+
78+
function void kmac_app_agent_cfg::add_user_digest(rsp_digest_t rsp_digest_h);
79+
if (if_mode != Device) begin
80+
`uvm_fatal(get_name(), $sformatf("Cannot add a digest: agent is in %0s mode.", if_mode.name()))
81+
end
82+
83+
rsp_digest_hs.push_back(rsp_digest_h);
84+
endfunction
85+
86+
function rsp_digest_t kmac_app_agent_cfg::pop_user_digest();
87+
if (!has_user_digest()) begin
88+
`uvm_fatal(get_name(), "Cannot get a user digest: the queue is empty.")
89+
end
90+
return rsp_digest_hs.pop_front();
91+
endfunction
92+
93+
function bit kmac_app_agent_cfg::has_user_digest();
94+
return (rsp_digest_hs.size() > 0);
95+
endfunction
96+
97+
constraint kmac_app_agent_cfg::zero_delays_c {
98+
zero_delays dist { 0 := 8, 1 := 2 };
99+
}

hw/dv/sv/kmac_app_agent/kmac_app_agent_cov.sv

Lines changed: 0 additions & 15 deletions
This file was deleted.

hw/dv/sv/kmac_app_agent/kmac_app_agent_pkg.sv

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,44 @@
55
package kmac_app_agent_pkg;
66
// dep packages
77
import uvm_pkg::*;
8-
import dv_utils_pkg::*;
9-
import dv_base_agent_pkg::*;
10-
import dv_lib_pkg::*;
11-
import keymgr_pkg::*;
12-
import push_pull_agent_pkg::*;
8+
9+
import dv_utils_pkg::Host, dv_utils_pkg::Device;
10+
11+
import dv_base_agent_pkg::dv_base_agent_cfg;
12+
import dv_base_agent_pkg::dv_base_agent_cov;
13+
import dv_base_agent_pkg::dv_base_driver;
14+
import dv_base_agent_pkg::dv_base_monitor;
15+
import dv_base_agent_pkg::dv_base_sequencer;
16+
import dv_base_agent_pkg::dv_base_agent;
17+
import dv_base_agent_pkg::dv_base_seq;
18+
19+
import kmac_pkg::AppDigestW, kmac_pkg::MsgWidth;
20+
import kmac_pkg::rsp_digest_t;
1321

1422
// macro includes
1523
`include "uvm_macros.svh"
1624
`include "dv_macros.svh"
1725

18-
// parameters
19-
parameter int KMAC_REQ_DATA_WIDTH = 2 * kmac_pkg::MsgWidth // share0 + share1
20-
+ kmac_pkg::MsgWidth / 8 // strobe
21-
+ 2; // req_last + rsp_ready
26+
`include "kmac_app_req_item.sv"
27+
`include "kmac_app_req_packet_item.sv"
28+
`include "kmac_app_rsp_item.sv"
29+
`include "kmac_app_mon_item.sv"
2230

23-
`define CONNECT_DATA_WIDTH .HostDataWidth(kmac_app_agent_pkg::KMAC_REQ_DATA_WIDTH)
24-
25-
// package sources
26-
`include "kmac_app_item.sv"
2731
`include "kmac_app_agent_cfg.sv"
28-
`include "kmac_app_sequencer.sv"
29-
`include "kmac_app_agent_cov.sv"
30-
`include "kmac_app_driver.sv"
31-
`include "kmac_app_host_driver.sv"
32-
`include "kmac_app_device_driver.sv"
32+
typedef dv_base_agent_cov #(.CFG_T (kmac_app_agent_cfg)) kmac_app_agent_cov;
3333
`include "kmac_app_monitor.sv"
34-
`include "kmac_app_seq_list.sv"
35-
`include "kmac_app_agent.sv"
34+
35+
`include "kmac_app_device_driver.sv"
36+
`include "kmac_app_device_sequencer.sv"
37+
38+
`include "kmac_app_host_driver.sv"
39+
typedef dv_base_sequencer #(.ITEM_T (kmac_app_req_item),
40+
.CFG_T (kmac_app_agent_cfg)) kmac_app_host_sequencer;
41+
42+
`include "seq_lib/kmac_app_device_seq.sv"
43+
`include "seq_lib/kmac_app_host_seq.sv"
44+
45+
`include "kmac_app_device_agent.sv"
46+
`include "kmac_app_host_agent.sv"
3647

3748
endpackage: kmac_app_agent_pkg
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright lowRISC contributors (OpenTitan project).
2+
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
class kmac_app_device_agent extends dv_base_agent #(.CFG_T (kmac_app_agent_cfg),
6+
.DRIVER_T (kmac_app_device_driver),
7+
.SEQUENCER_T (kmac_app_device_sequencer),
8+
.MONITOR_T (kmac_app_monitor),
9+
.COV_T (kmac_app_agent_cov));
10+
`uvm_component_utils(kmac_app_device_agent)
11+
12+
extern function new(string name, uvm_component parent);
13+
extern function void build_phase(uvm_phase phase);
14+
extern function void connect_phase(uvm_phase phase);
15+
16+
// A task that runs the standard kmac_app_device_seq to respond to app requests
17+
//
18+
// This sequence never completes
19+
extern task run_device_seq();
20+
endclass
21+
22+
function kmac_app_device_agent::new(string name, uvm_component parent);
23+
super.new(name, parent);
24+
endfunction
25+
26+
function void kmac_app_device_agent::build_phase(uvm_phase phase);
27+
super.build_phase(phase);
28+
29+
// Get the handle to the interface
30+
if (!uvm_config_db#(virtual kmac_app_if)::get(this, "", "vif", cfg.vif)) begin
31+
`uvm_fatal(`gfn, "failed to get kmac_app_if handle from uvm_config_db")
32+
end
33+
34+
// Configure the interface to match the agent.
35+
cfg.vif.if_mode = Device;
36+
endfunction
37+
38+
function void kmac_app_device_agent::connect_phase(uvm_phase phase);
39+
super.connect_phase(phase);
40+
41+
if (cfg.is_active) begin
42+
// Connect requests from the driver to the sequencer
43+
driver.m_req_port.connect(sequencer.m_req_fifo.analysis_export);
44+
end
45+
endfunction
46+
47+
task kmac_app_device_agent::run_device_seq();
48+
kmac_app_device_seq seq = kmac_app_device_seq::type_id::create("seq");
49+
if (!seq.randomize()) `uvm_fatal(get_full_name(), "Failed to randomize device seq")
50+
seq.start(sequencer);
51+
endtask

0 commit comments

Comments
 (0)