[aes/dv] added coverage outline to aes
Signed-off-by: Rasmus Madsen <rasmus.madsen@wdc.com>
diff --git a/hw/ip/aes/dv/aes_sim.core b/hw/ip/aes/dv/aes_sim.core
index 514746f..b2b2023 100644
--- a/hw/ip/aes/dv/aes_sim.core
+++ b/hw/ip/aes/dv/aes_sim.core
@@ -13,6 +13,7 @@
depend:
- lowrisc:dv:aes_test
- lowrisc:dv:aes_sva
+ - lowrisc:dv:aes_cov
files:
- tb/tb.sv
file_type: systemVerilogSource
diff --git a/hw/ip/aes/dv/aes_sim_cfg.hjson b/hw/ip/aes/dv/aes_sim_cfg.hjson
index db595d4..16e84b6 100644
--- a/hw/ip/aes/dv/aes_sim_cfg.hjson
+++ b/hw/ip/aes/dv/aes_sim_cfg.hjson
@@ -37,7 +37,7 @@
// "{proj_root}/hw/dv/tools/dvsim/tests/stress_tests.hjson"]
// Add additional tops for simulation.
- sim_tops: ["aes_bind"]
+ sim_tops: [ "aes_bind", "aes_cov_bind"]
// Default iterations for all tests - each test entry can override this.
reseed: 50
diff --git a/hw/ip/aes/dv/cov/aes_cov.core b/hw/ip/aes/dv/cov/aes_cov.core
new file mode 100644
index 0000000..8296517
--- /dev/null
+++ b/hw/ip/aes/dv/cov/aes_cov.core
@@ -0,0 +1,21 @@
+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:aes_cov"
+description: "AES functional coverage interface & bind."
+
+filesets:
+ files_dv:
+ depend:
+ - lowrisc:dv:dv_utils
+ - lowrisc:ip:aes:0.6
+ files:
+ - aes_cov_if.sv
+ - aes_cov_bind.sv
+ file_type: systemVerilogSource
+
+targets:
+ default:
+ filesets:
+ - files_dv
diff --git a/hw/ip/aes/dv/cov/aes_cov_bind.sv b/hw/ip/aes/dv/cov/aes_cov_bind.sv
new file mode 100644
index 0000000..37f9fdf
--- /dev/null
+++ b/hw/ip/aes/dv/cov/aes_cov_bind.sv
@@ -0,0 +1,12 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Binds UART functional coverage interaface to the top level AES module.
+module aes_cov_bind;
+
+ bind aes aes_cov_if u_aes_cov_if (
+ .clk_i (clk_i)
+ );
+
+endmodule
diff --git a/hw/ip/aes/dv/cov/aes_cov_if.sv b/hw/ip/aes/dv/cov/aes_cov_if.sv
new file mode 100644
index 0000000..1d504ec
--- /dev/null
+++ b/hw/ip/aes/dv/cov/aes_cov_if.sv
@@ -0,0 +1,157 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Implements functional coverage for AES
+
+interface aes_cov_if
+ (
+ input logic clk_i // not sure I will use this yet
+ );
+
+ import uvm_pkg::*;
+ import aes_pkg::*;
+ import dv_utils_pkg::*;
+ `include "dv_fcov_macros.svh"
+
+ bit en_full_cov = 1'b1;
+ bit en_intg_cov = 1'b1;
+
+ ///////////////////////////////////
+ // Control register cover points //
+ ///////////////////////////////////
+
+ covergroup aes_ctrl_cg with function sample(bit aes_op,
+ bit [aes_pkg::AES_MODE_WIDTH-1:0] aes_mode,
+ bit [aes_pkg::AES_KEYLEN_WIDTH-1:0] aes_keylen,
+ bit aes_man_op,
+ bit aes_force_0mask
+ );
+ option.per_instance = 1;
+ option.name = "aes_ctrl_cg";
+
+ cp_operation: coverpoint aes_op
+ {
+ bins enc = {AES_ENC};
+ bins dec = {AES_DEC};
+ }
+
+ cp_mode: coverpoint aes_mode
+ {
+ bins ecb = { AES_ECB};
+ bins cbc = { AES_CBC };
+ bins cfb = { AES_CFB };
+ bins ofb = { AES_OFB };
+ bins ctr = { AES_CTR };
+ bins none = { AES_NONE };
+ bins illegal = { [0:$] } with ($countones(item) != 1);
+ }
+
+ cp_key_len: coverpoint aes_keylen
+ {
+ bins aes_128 = {AES_128};
+ bins aes_192 = {AES_192};
+ bins aes_256 = {AES_256};
+ bins illegal = { [0:$] } with ($countones(item) != 1);
+ }
+
+ cp_manual_operation: coverpoint aes_man_op
+ {
+ bins auto_mode = { 1'b0 };
+ bins manual_mode = { 1'b1 };
+ }
+
+ cp_force_0_masks: coverpoint aes_force_0mask;
+
+ // Cross coverage points
+ // All key_lens are tested in all modes
+ cr_mode_key_len: cross cp_mode, cp_key_len;
+ // all modes are tested in both auto an manual operation
+ cr_mode_man_op: cross cp_mode, cp_manual_operation;
+ // All modes used in both incryption and decryption
+ cr_mode_op: cross cp_mode, cp_operation;
+ endgroup // aes_ctrl_cg
+
+
+ ///////////////////////////////////
+ // Status register cover points //
+ ///////////////////////////////////
+
+ covergroup aes_status_cg with function sample(status_t aes_status);
+ option.per_instance = 1;
+ option.name = "aes_status_cg";
+ endgroup // aes_status_cg
+
+
+ ///////////////////////////////////
+ // Trigger register cover points //
+ ///////////////////////////////////
+
+ covergroup aes_trigger_cg with function sample(bit aes_start,
+ bit aes_key_iv_datain_clear,
+ bit aes_dataout_clear,
+ bit aes_prng_reseed
+ );
+ option.per_instance = 1;
+ option.name = "aes_trigger_cg";
+
+ cp_start: coverpoint aes_start;
+ cp_key_iv_datain_clear: coverpoint aes_key_iv_datain_clear;
+ cp_dataout_clear: coverpoint aes_dataout_clear;
+ cp_prng_reseed: coverpoint aes_prng_reseed;
+
+ cr_clear: cross cp_key_iv_datain_clear, cp_dataout_clear;
+
+ endgroup // aes_trigger_cg
+
+ ///////////////////////////////////
+ // Alert register cover points //
+ ///////////////////////////////////
+
+ covergroup aes_alert_cg with function sample(alert_test_t alert_test);
+ option.per_instance = 1;
+ option.name = "aes_test_alert_cg";
+ endgroup // aes_alert_cg
+
+
+ ///////////////////////////////////
+ // Instantiation Macros //
+ ///////////////////////////////////
+
+ `DV_FCOV_INSTANTIATE_CG(aes_ctrl_cg, en_full_cov)
+ `DV_FCOV_INSTANTIATE_CG(aes_status_cg, en_full_cov)
+ `DV_FCOV_INSTANTIATE_CG(aes_trigger_cg, en_full_cov)
+ `DV_FCOV_INSTANTIATE_CG(aes_alert_cg, en_full_cov)
+
+
+ ///////////////////////////////////
+ // Sample functions //
+ // needed for xcelium //
+ ///////////////////////////////////
+
+ function automatic void cg_ctrl_sample(bit aes_op,
+ bit [aes_pkg::AES_MODE_WIDTH-1:0] aes_mode,
+ bit [aes_pkg::AES_KEYLEN_WIDTH-1:0] aes_keylen,
+ bit aes_man_op,
+ bit aes_force_0mask
+ );
+ aes_ctrl_cg_inst.sample(aes_op, aes_mode, aes_keylen, aes_man_op, aes_force_0mask);
+ endfunction
+
+ function automatic void cg_status_sample(bit [31:0] val);
+ aes_status_cg_inst.sample(val);
+ endfunction
+
+ function automatic void cg_trigger_sample(bit aes_start,
+ bit aes_key_iv_datain_clear,
+ bit aes_dataout_clear,
+ bit aes_prng_reseed
+ );
+ aes_trigger_cg_inst.sample(aes_start, aes_key_iv_datain_clear, aes_dataout_clear, aes_prng_reseed);
+ endfunction
+
+ function automatic void cg_alert_test_sample(bit [31:0] val);
+ aes_alert_cg_inst.sample(val);
+ endfunction
+
+endinterface
diff --git a/hw/ip/aes/dv/env/aes_env.core b/hw/ip/aes/dv/env/aes_env.core
index 636bf8b..9f26142 100644
--- a/hw/ip/aes/dv/env/aes_env.core
+++ b/hw/ip/aes/dv/env/aes_env.core
@@ -14,6 +14,7 @@
- lowrisc:dv:cip_lib
- lowrisc:dv:csr_utils
- lowrisc:dv:aes_model_dpi
+ - lowrisc:dv:aes_cov
files:
- aes_env_pkg.sv
- aes_seq_item.sv: {is_include_file: true}
diff --git a/hw/ip/aes/dv/env/aes_env_pkg.sv b/hw/ip/aes/dv/env/aes_env_pkg.sv
index a3f1294..c90c856 100644
--- a/hw/ip/aes/dv/env/aes_env_pkg.sv
+++ b/hw/ip/aes/dv/env/aes_env_pkg.sv
@@ -43,17 +43,6 @@
bit mode;
} cfg_error_type_t;
- typedef struct packed {
- logic [31:7] unused;
- logic alert_fatal_fault;
- logic alert_recov_ctrl_update_err;
- logic input_ready;
- logic output_valid;
- logic output_lost;
- logic stall;
- logic idle;
- } status_t;
-
// package sources
`include "aes_env_cfg.sv"
diff --git a/hw/ip/aes/dv/env/aes_message_item.sv b/hw/ip/aes/dv/env/aes_message_item.sv
index a952de2..a57f4ed 100644
--- a/hw/ip/aes/dv/env/aes_message_item.sv
+++ b/hw/ip/aes/dv/env/aes_message_item.sv
@@ -184,7 +184,7 @@
constraint c_manual_operation {
manual_operation dist { 0:/ (100 - manual_operation_pct),
1:/ manual_operation_pct};
- };
+ }
function void add_data_item(aes_seq_item item);
diff --git a/hw/ip/aes/dv/env/aes_scoreboard.sv b/hw/ip/aes/dv/env/aes_scoreboard.sv
index af66900..ee7d1f9 100644
--- a/hw/ip/aes/dv/env/aes_scoreboard.sv
+++ b/hw/ip/aes/dv/env/aes_scoreboard.sv
@@ -26,6 +26,7 @@
int corrupt_cnt = 0; // number of aes_mode errors seen
int skipped_cnt = 0; // number of skipped messages
+ virtual aes_cov_if cov_if; // handle to aes coverage interface
// local queues to hold incoming packets pending comparison //
// Items containing both input and output data, ready to be added to a message
@@ -42,6 +43,10 @@
item_fifo = new();
input_item = new("input_item");
output_item = new ();
+
+ if (!uvm_config_db#(virtual aes_cov_if)::get(null, "*.env" , "aes_cov_if", cov_if)) begin
+ `uvm_fatal(`gfn, $sformatf("FAILED TO GET HANDLE TO COVER IF"))
+ end
endfunction
@@ -87,13 +92,20 @@
csr_name = csr.get_name();
case (1)
// add individual case item for each csr
+ (!uvm_re_match("alert_test", csr_name)): begin
+ // TODO
+ cov_if.cg_alert_test_sample(item.a_data);
+ end
+
+
(!uvm_re_match("ctrl_shadowed", csr_name)): begin
if (write) begin
- input_item.manual_op = item.a_data[10];
- input_item.key_len = item.a_data[9:7];
- `downcast(input_item.operation, item.a_data[0]);
+// cov_if.cg_ctrl_sample(item.a_data);
+ input_item.manual_op = get_field_val(ral.ctrl_shadowed.manual_operation, item.a_data);
+ input_item.key_len = get_field_val(ral.ctrl_shadowed.key_len, item.a_data);
+ `downcast(input_item.operation, get_field_val(ral.ctrl_shadowed.operation ,item.a_data));
input_item.valid = 1'b1;
- case (item.a_data[6:1])
+ case (get_field_val(ral.ctrl_shadowed.mode, item.a_data))
6'b00_0001: input_item.mode = AES_ECB;
6'b00_0010: input_item.mode = AES_CBC;
6'b00_0100: input_item.mode = AES_CFB;
@@ -101,7 +113,15 @@
6'b01_0000: input_item.mode = AES_CTR;
6'b10_0000: input_item.mode = AES_NONE;
default: input_item.mode = AES_NONE;
- endcase // case item.a_data[4:1]
+ endcase
+ // sample coverage on ctrl register
+ cov_if.cg_ctrl_sample(get_field_val(ral.ctrl_shadowed.operation, item.a_data),
+ get_field_val(ral.ctrl_shadowed.mode, item.a_data),
+ get_field_val(ral.ctrl_shadowed.key_len, item.a_data),
+ get_field_val(ral.ctrl_shadowed.manual_operation, item.a_data),
+ get_field_val(ral.ctrl_shadowed.force_zero_masks, item.a_data)
+ );
+
input_item.clean();
input_item.start_item = 1;
end
@@ -149,6 +169,11 @@
(!uvm_re_match("trigger", csr_name)): begin
//start triggered
+ cov_if.cg_trigger_sample(get_field_val(ral.trigger.start, item.a_data),
+ get_field_val(ral.trigger.key_iv_data_in_clear, item.a_data),
+ get_field_val(ral.trigger.data_out_clear, item.a_data),
+ get_field_val(ral.trigger.prng_reseed, item.a_data)
+ );
`uvm_info(`gfn, $sformatf("\n CLEAR REGISTER SEEN 0x%h", item.a_data), UVM_MEDIUM)
if (get_field_val(ral.trigger.start, item.a_data)) begin
ok_to_fwd = 1;
@@ -188,9 +213,9 @@
end
end
- // "status": begin
- // //TBD
- // end
+ // (!uvm_re_match("status", csr_name)): begin
+ // // not used in scoreboard
+ // end
default: begin
// DO nothing- trying to write to a read only register
@@ -359,7 +384,10 @@
output_item.data_out[3] = item.d_data;
output_item.data_out_vld[3] = 1;
end
+
"status": begin
+ cov_if.cg_status_sample(item.d_data);
+
// if dut IDLE and able to accept input
// and no output is ready
// there won't be a response for this item
diff --git a/hw/ip/aes/dv/env/seq_lib/aes_base_vseq.sv b/hw/ip/aes/dv/env/seq_lib/aes_base_vseq.sv
index ebd4a66..8f1d797 100644
--- a/hw/ip/aes/dv/env/seq_lib/aes_base_vseq.sv
+++ b/hw/ip/aes/dv/env/seq_lib/aes_base_vseq.sv
@@ -82,26 +82,34 @@
virtual task set_operation(bit operation);
- ral.ctrl_shadowed.operation.set(operation);
- csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+ if (ral.ctrl_shadowed.operation.get_mirrored_value() != operation) begin
+ ral.ctrl_shadowed.operation.set(operation);
+ csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+ end
endtask // set_operation
virtual task set_mode(bit [5:0] mode);
- ral.ctrl_shadowed.mode.set(mode);
- csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+ if (ral.ctrl_shadowed.mode.get_mirrored_value() != mode) begin
+ ral.ctrl_shadowed.mode.set(mode);
+ csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+ end
endtask
virtual task set_key_len(bit [2:0] key_len);
- ral.ctrl_shadowed.key_len.set(key_len);
- csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+ if (ral.ctrl_shadowed.key_len.get_mirrored_value() != key_len) begin
+ ral.ctrl_shadowed.key_len.set(key_len);
+ csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+ end
endtask
virtual task set_manual_operation(bit manual_operation);
- ral.ctrl_shadowed.manual_operation.set(manual_operation);
- csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+ if (ral.ctrl_shadowed.manual_operation.get_mirrored_value() != manual_operation) begin
+ ral.ctrl_shadowed.manual_operation.set(manual_operation);
+ csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+ end
endtask
diff --git a/hw/ip/aes/dv/tb/tb.sv b/hw/ip/aes/dv/tb/tb.sv
index ba71b2b..783c2bb 100644
--- a/hw/ip/aes/dv/tb/tb.sv
+++ b/hw/ip/aes/dv/tb/tb.sv
@@ -25,6 +25,7 @@
pins_if #(1) devmode_if(devmode);
tl_if tl_if(.clk(clk), .rst_n(rst_n));
+
`DV_ALERT_IF_CONNECT
// dut
@@ -53,6 +54,8 @@
uvm_config_db#(intr_vif)::set(null, "*.env", "intr_vif", intr_if);
uvm_config_db#(devmode_vif)::set(null, "*.env", "devmode_vif", devmode_if);
uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent*", "vif", tl_if);
+ uvm_config_db#(virtual aes_cov_if)::set(null, "*.env", "aes_cov_if", dut.u_aes_cov_if );
+
$timeformat(-12, 0, " ps", 12);
run_test();
end
diff --git a/hw/ip/aes/dv/tests/aes_smoke_test.sv b/hw/ip/aes/dv/tests/aes_smoke_test.sv
index c4baeb9..8290f91 100644
--- a/hw/ip/aes/dv/tests/aes_smoke_test.sv
+++ b/hw/ip/aes/dv/tests/aes_smoke_test.sv
@@ -16,8 +16,8 @@
function void configure_env();
super.configure_env();
cfg.error_types = 0; // no errors in smoke test
- cfg.num_messages_min = 2;
- cfg.num_messages_max = 2;
+ cfg.num_messages_min = 3;
+ cfg.num_messages_max = 3;
// message related knobs
cfg.ecb_weight = 10;
cfg.cbc_weight = 10;