diff --git a/hw/top_chip/dv/axi_sram/axi_sram_vplan.hjson b/hw/top_chip/dv/axi_sram/data/axi_sram_vplan.hjson similarity index 76% rename from hw/top_chip/dv/axi_sram/axi_sram_vplan.hjson rename to hw/top_chip/dv/axi_sram/data/axi_sram_vplan.hjson index fd75aaf68..b1be7afe5 100644 --- a/hw/top_chip/dv/axi_sram/axi_sram_vplan.hjson +++ b/hw/top_chip/dv/axi_sram/data/axi_sram_vplan.hjson @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -// TODO: Add metrics for each item in the vPlan (issue #696) { axi_sram: { @@ -21,6 +20,10 @@ Description: The SRAM block should have four ports: clock / reset / AXI4 request in / AXI4 response out Node_Type: metric Priority: 0 + Items: + [ + assert:TODO_interface_geometry + ] } sram_geometry: { @@ -34,6 +37,10 @@ Node_Type: metric Priority: 0 Comment: SramMemSize 128 KiB, last word 0x1FFF8 and last cap slot 0x1FFF0 are derived from SRAMLength in top_pkg (0x2_0000) and 5scstu. + Items: + [ + assert:TODO_sram_geometry + ] } } Data_Path: @@ -54,6 +61,10 @@ Description: DUT should come out of reset cleanly and should accept the first transaction Node_Type: metric Priority: 0 + Items: + [ + testcase:axi_sram_rst_sanity_test + ] } rst_mid_burst: { @@ -62,6 +73,10 @@ Node_Type: metric Priority: 0 Comment: Transaction should be dropped cleanly. The next transaction after an in-flight reset should still be accepted as normal. Would be good to clarification on the expected state of SRAM after a reset (i.e if a reset comes in during a 2-beat capability write) + Items: + [ + testcase:TODO_rst_mid_burst + ] } init_value_undefined: { @@ -70,6 +85,10 @@ Node_Type: metric Priority: 2 Comment: We model this by not pre-loading the SRAM (leave a X's). Not an explicit testcase, rather an environment configuration. + Items: + [ + testcase:axi_sram_init_value_undefined_test + ] } } Basic_access: @@ -87,6 +106,10 @@ Description: Single-beat 8-byte write followed by readback should return identical data Node_Type: metric Priority: 0 + Items: + [ + testcase:axi_sram_write_read_test + ] } address_boundaries: { @@ -94,6 +117,10 @@ Description: Write/read first (0x0) and last valid word (0x1FFF8) and last capability slot (0x1FFF0) Node_Type: metric Priority: 0 + Items: + [ + testcase:axi_sram_address_boundaries_test + ] } data_all_bits: { @@ -101,6 +128,10 @@ Description: Walk a 1 and a 0 through all 64 data bits to catch stuck-at faults Node_Type: metric Priority: 0 + Items: + [ + testcase:axi_sram_data_all_bits_test + ] } aligned_only: { @@ -108,6 +139,10 @@ Description: Only aligned 64-bit accesses are exercised; misaligned data accesses are not expected/supported Node_Type: metric Priority: 1 + Items: + [ + testcase:axi_sram_aligned_only_test + ] } } Bursts: @@ -124,6 +159,10 @@ Description: Last beat of a burst should assert rlast and should expect wlast correctly Node_Type: metric Priority: 0 + Items: + [ + testcase:axi_sram_burst_last_test + ] } resp_id_match: { @@ -132,6 +171,10 @@ Node_Type: metric Priority: 0 Comment: Checked explicitly by the SV scoreboard + Items: + [ + testcase:axi_sram_resp_id_match_test + ] } atomic_excluded: { @@ -139,6 +182,10 @@ Description: Atomic support is excluded, so an access carrying a non-zero awatop must be answered with a slave error rather than being serviced. Drive ATOP_ATOMICSTORE (awatop[5:4]=01), ATOP_ATOMICLOAD (10), ATOP_ATOMICSWAP (6'b110000) and ATOP_ATOMICCMP (6'b110001) at an in-range address and check that bresp is RESP_SLVERR (2'b10) with the request ID, that the atop[5] classes which also return read data report rresp RESP_SLVERR on every R beat with rlast on the final beat, that the addressed memory is left unchanged, and that the CHERI tag of the covering 128-bit slot is left unchanged because the rejected access must not write. A plain access to the same address afterwards must still succeed, so the error must not wedge the block Node_Type: metric Priority: 1 + Items: + [ + testcase:axi_sram_atomics_excluded_test + ] } bounded_response: { @@ -146,6 +193,10 @@ Description: Every request should receive a response within a bounded time proportional to burst length Node_Type: metric Priority: 1 + Items: + [ + assert:TODO_bounded_response + ] } backpressure: { @@ -153,6 +204,10 @@ Description: Master side constrained random ready-throttling under load. the VIP holds r_ready/b_ready low with a random low duty cycle and injects valid-delays on the request channels (aw/w/ar), forcing the DUT's shallow internal FIFOs to fill and deassert its own aw_ready/w_ready/ar_ready. Data and CHERI tag must be intact once the master resumes. Node_Type: metric Priority: 1 + Items: + [ + testcase:TODO_backpressure + ] } } Concurrency: @@ -165,6 +220,10 @@ Description: A plain-data write and a capability write issued concurrently should both complete and should read back correctly Node_Type: metric Priority: 1 + Items: + [ + testcase:axi_sram_concurrent_data_tag_test + ] } multiple_outstanding_transactions: { @@ -172,6 +231,10 @@ Description: multiple reads+writes to distinct addresses in flight should all complete, data+tag should be correct, and ids should match Node_Type: metric Priority: 1 + Items: + [ + testcase:TODO_multiple_outstanding_transactions + ] } waw_same_address: { @@ -179,6 +242,10 @@ Description: back-to-back writes to the same address+tag should result in the last write data+tag being read back. Node_Type: metric Priority: 1 + Items: + [ + testcase:TODO_waw_same_address + ] } raw_war_same_region: { @@ -187,6 +254,10 @@ Node_Type: metric Priority: 2 Comment: both old and new data are legal outcomes (axi doesn't mandate how the race is handled), so the scoreboard is relaxed on value. Still, the racing read's data must equal the pre or post-write value fully (not bit-torn or X), each beat of a multi-beat read is independently a clean old or new value, and the CHERI tag (ruser) must be consistent with whichever data snapshot that beat observed. Strict invariants are still checked: no deadlock, both transactions receive responses with correct ID / BRESP / RRESP / RLAST. a subsequent ordered read returns the new data (RAW) and the final stored value equals the write data (WAR). + Items: + [ + testcase:TODO_raw_war_same_region + ] } } } @@ -204,6 +275,10 @@ Description: Each data field should have a corresponding tag field which should be accessible in the same transaction Node_Type: metric Priority: 0 + Items: + [ + testcase:axi_sram_tag_write_test + ] } no_tag_single_beat: { @@ -216,6 +291,10 @@ Node_Type: metric Priority: 0 Comment: Corner: tag only on full capability burst + Items: + [ + testcase:axi_sram_no_tag_single_beat_test + ] } no_tag_misaligned: { @@ -224,6 +303,10 @@ Node_Type: metric Priority: 1 Comment: Corner: alignment gating + Items: + [ + testcase:axi_sram_no_tag_misaligned_test + ] } no_tag_two_bursts: { @@ -236,6 +319,10 @@ Node_Type: metric Priority: 1 Comment: Corner: full region covered across two separate bursts still leaves the tag 0 + Items: + [ + testcase:axi_sram_no_tag_two_bursts_test + ] } assert_wuser_not_full_cap: { @@ -243,6 +330,10 @@ Description: Assertion should fire when wuser=1 on a write that is not part of a full capability write Node_Type: metric Priority: 1 + Items: + [ + assert:TODO_assert_wuser_not_full_cap + ] } assert_wuser_mismatch: { @@ -255,6 +346,27 @@ Node_Type: metric Priority: 1 Comment: The two orders are not equivalent, so neither may be dropped. The tag RAM is written on every beat - u_tag_ram.write_i is sram_we_d - and both beats of a 2-beat capability write resolve to the same tag bit, because sram_tag_bit_addr is the byte address shifted right by $clog2(CapSizeBits/8) and that is identical for X and X+8. The stored value is therefore the last beat's cheri_w_tag, which is w.user & is_w_cap_sized & is_w_cap_aligned (axi_to_detailed_mem.sv:414) and reduces to the last beat's wuser for an aligned, correctly sized burst. So (1, 0) stores 0 and passes, while (0, 1) stores 1 - a forged capability tag on a write that was never a full capability write. Stated against the architectural requirement, so the testpoint stays valid whatever the RTL currently does + Items: + [ + assert:TODO_assert_wuser_mismatch + testcase:axi_sram_wuser_mismatch_test + ] + } + cg_tag_write: + { + Reference: + ''' + 8rlwol + 35vdeg + 893tz4 + ''' + Description: Coverage of the tag-write gating conditions (burst length/size, alignment, strobe, wuser), each crossed with the tag bit. + Node_Type: metric + Priority: 1 + Items: + [ + functional:axi_sram_cov::cg_tag_write + ] } } Tag_clear: @@ -268,6 +380,10 @@ Node_Type: metric Priority: 0 Comment: Corner: any non-cap write zeroes the tag bit + Items: + [ + testcase:axi_sram_tag_cleared_by_write_test + ] } partial_strobe_clears_tag: { @@ -276,6 +392,10 @@ Node_Type: metric Priority: 1 Comment: Corner: partial strobe clears tag + Items: + [ + testcase:axi_sram_partial_strobe_clears_tag_test + ] } subword_read_clears_tag: { @@ -288,6 +408,10 @@ Node_Type: metric Priority: 1 Comment: Tag is returned as clear in the response, but not modified in memory. + Items: + [ + testcase:axi_sram_subword_read_clears_tag_test + ] } } Tag_read: @@ -306,6 +430,11 @@ Node_Type: metric Priority: 0 Comment: the SRAM invalidate a cap by clearing one or both `ruser` bits, so the two flits are not guaranteed equal by spec. Rather than treat the asymmetric (1,0) case as not-applicable, bind an SVA that on every 2-beat capability read both flits are equal and match the single stored tag bit (ruser_flit0 == ruser_flit1). This proves the one-bit-per-region design never emits a false-valid asymmetric result. + Items: + [ + assert:TODO_cap_both_ruser_set + testcase:axi_sram_cap_ruser_test + ] } burst_read_mixed_tags: { @@ -313,6 +442,25 @@ Description: A read spanning a tagged and an untagged capability slot should return the correct per-beat ruser for each Node_Type: metric Priority: 2 + Items: + [ + testcase:axi_sram_burst_read_mixed_tags_test + ] + } + cg_tag_read: + { + Reference: + ''' + kn6exz + raa5pw + ''' + Description: Coverage of the ruser tag returned on reads: the per-flit tag pair on capability reads, and cleared tags on sub-word reads + Node_Type: metric + Priority: 1 + Items: + [ + functional:axi_sram_cov::cg_tag_read + ] } } Tag_isolation: @@ -325,6 +473,10 @@ Description: Writing/clearing the tag of one 128-bit slot must not affect an adjacent slot's tag Node_Type: metric Priority: 0 + Items: + [ + testcase:axi_sram_tag_isolation_test + ] } tag_aliasing: { @@ -333,6 +485,10 @@ Node_Type: metric Priority: 0 Comment: The i+1024 stride targets a suspected tag address truncation in axi_sram.sv. TagBitAddrWidth subtracts a byte-based shift ($clog2(CapSizeBits/8) = 4) from AddrWidth, which is a 64-bit-word width, giving 10 instead of $clog2(CapSizeBits/AxiDataWidth) = 1 subtracted for 13. u_tag_ram is then 16 x 64 = 1024 tag bits for the 8192 slots in 128 KiB, aliasing every 16 KiB. The metric is written against the architectural requirement so it stays valid once the width is corrected, at which point no stride aliases + Items: + [ + testcase:TODO_tag_aliasing + ] } tag_separate_memory: { @@ -340,6 +496,10 @@ Description: Tags should be stored in a separate memory block from data Node_Type: metric Priority: 2 + Items: + [ + assert:TODO_tag_separate_memory + ] } } } @@ -354,6 +514,10 @@ Description: N random (aligned addr, data) write/read pairs across the address space Node_Type: metric Priority: 1 + Items: + [ + testcase:axi_sram_random_data_test + ] } random_capabilities: { @@ -365,34 +529,10 @@ Description: N random 16-byte-aligned capability write/read pairs verifying data and tag Node_Type: metric Priority: 1 - } - } - Coverage: - { - Description: Functional coverage collection for the AXI SRAM - Node_Type: section_title - cg_tag_write: - { - Reference: - ''' - 8rlwol - 35vdeg - 893tz4 - ''' - Description: Coverage of the tag-write gating conditions (burst length/size, alignment, strobe, wuser), each crossed with the tag bit. - Node_Type: metric - Priority: 1 - } - cg_tag_read: - { - Reference: - ''' - kn6exz - raa5pw - ''' - Description: Coverage of the ruser tag returned on reads: the per-flit tag pair on capability reads, and cleared tags on sub-word reads - Node_Type: metric - Priority: 1 + Items: + [ + testcase:axi_sram_random_capabilities_test + ] } } } @@ -411,6 +551,10 @@ Node_Type: metric Priority: 0 Comment: Implicit + Items: + [ + testcase:TODO_sram_reachable + ] } out_of_range_error: { @@ -419,6 +563,11 @@ Node_Type: metric Priority: 1 Comment: Fully-out-of-range accesses result in an error; the partial-out-of-range part is enforced by proxy of AXI4 not allowing bursts to span a 4KB boundary + Items: + [ + testcase:axi_sram_out_of_range_error_test + testcase:axi_sram_wrong_region_decerr_test + ] } burst_wrap: { @@ -427,6 +576,10 @@ Node_Type: metric Priority: 2 Comment: AXI4 forbids a burst from crossing a 4 KB boundary, so a compliant master can't issue such a burst. axi_sram itself does not range-check (mem_err_i=0; it masks the address and would silently wrap), so range enforcement rests entirely on the AXI driver being compliant. + Items: + [ + testcase:axi_sram_burst_wrap_test + ] } sram_boundary: { @@ -434,6 +587,10 @@ Description: Address range edges: the first and last SRAM words should round-trip OK; the word just below SRAMBase and the word just past the top are unmapped and should return DECERR Node_Type: metric Priority: 1 + Items: + [ + testcase:axi_sram_sram_boundary_test + ] } execute_from_sram: { @@ -442,6 +599,10 @@ Node_Type: metric Priority: 2 Comment: only the arprot[2]=instruction dimension is SRAM-specific + Items: + [ + testcase:axi_sram_execute_from_sram_test + ] } } }