Srikrishna Iyer | 86169d0 | 2021-05-10 09:35:52 -0700 | [diff] [blame] | 1 | --- |
| 2 | title: "Testplanner tool" |
| 3 | --- |
| 4 | |
| 5 | `testplanner` is a Python based tool for parsing testplans written in Hjson format into a data structure that can be used for: |
| 6 | * Expanding the testplan inline within the DV document as a table; |
| 7 | * Annotating the simulation results with testplan entries for a document driven DV execution; |
| 8 | |
| 9 | Please see [DV methodology]({{< relref "doc/ug/dv_methodology/index.md#documentation" >}}) for more details on the rationale and motivation for writing and maintaining testplans in a machine-parsable format (`Hjson`). |
| 10 | This document will focus on the anatomy of an Hjson testplan, the list of features supported and some of the ways of using the tool. |
| 11 | |
| 12 | ## Hjson testplan |
| 13 | |
| 14 | A testplan consists of a list of planned tests (testpoints) and a list of planned functional coverage items (covergroups). |
| 15 | |
| 16 | ### Testpoints |
| 17 | |
| 18 | A testpoint is an entry in the testplan representing a planned test. |
| 19 | Each testpoint maps one-to-one to a unique feature of the design. |
| 20 | Additionally, a testpoint for each of the [key areas of focus]({{< relref "doc/ug/dv_methodology/index.md#key-test-focus-areas" >}}) (whichever ones are applicable) is also captured in the testplan. |
| 21 | |
| 22 | The following attributes are used to define each testpoint, at minimum: |
| 23 | * **name: testpoint name** |
| 24 | |
| 25 | This is a single `lower_snake_case` string that succinctly describes the intended feature being tested. |
| 26 | As an example, a smoke test, which is typically the first test written for a new testbench would simply be called `smoke`. |
| 27 | A testpoint that focuses on erasing a page within a `flash_ctrl` bank would be called `page_erase`. |
| 28 | The recommended naming convention to follow is `<main_feature>_<sub_feature>_<sub_sub_feature_or_type>_...`. |
| 29 | This is no need to suffix (or prefix) the testpoint name with "test". |
| 30 | |
| 31 | * **milestone: targeted verification milestone** |
| 32 | |
Srikrishna Iyer | d0ff7c0 | 2021-10-05 21:52:11 -0700 | [diff] [blame] | 33 | This is either `V1`, `V2`, `V2S` or `V3`. |
Srikrishna Iyer | 86169d0 | 2021-05-10 09:35:52 -0700 | [diff] [blame] | 34 | It helps us track whether all of the testing requirements of a milestone have been achieved. |
| 35 | |
| 36 | * **desc: testpoint description** |
| 37 | |
| 38 | A multi-line string that briefly describes the intent of the test. |
| 39 | It is recommended, but not always necessary to add a high level goal, stimulus, and the checking procedure so that the reader gets a clear idea of what and how the said feature is going to be tested. |
| 40 | |
| 41 | Full [Markdown]({{< relref "doc/rm/markdown_usage_style" >}}) syntax is supported when writing the description. |
| 42 | |
| 43 | * **tests: list of written test(s) for a testpoint** |
| 44 | |
| 45 | The testplan is written in the initial work stage of the verification [life-cycle]({{< relref "doc/project/development_stages#hardware-verification-stages" >}}). |
| 46 | Later, when the DV engineer writes the tests, they may not map one-to-one to a testpoint - it may be possible that a written test satisfactorilly addresses multiple testpoints; OR it may also be possible that a testpoint needs to be split into multiple smaller tests. |
| 47 | To cater to these needs, we provide the ability to set a list of written tests for each testpoint. |
| 48 | It is used to not only indicate the current progress so far into each milestone, but also map the simulation results to the testpoints to generate the final report table. |
| 49 | This list is initially empty - it is gradually updated as tests are written. |
| 50 | |
| 51 | If the need arises, more attributes may be added relatively easily. |
| 52 | |
| 53 | Testpoints are added to the testplan using the `testpoints` key. |
| 54 | Here's an example: |
| 55 | ```hjson |
| 56 | testpoints: [ |
| 57 | { |
| 58 | name: feature1 |
| 59 | milestone: V1 |
| 60 | desc: '''**Goal**: High level goal of this test. |
| 61 | |
| 62 | **Stimulus**: Describe the stimulus procedure. |
| 63 | |
| 64 | **Check**: Describe the checking procedure.''' |
| 65 | tests: ["foo_feature1"] |
| 66 | } |
| 67 | { |
| 68 | name: feature2 |
| 69 | milestone: V2 |
| 70 | desc: '''**Goal**: High level goal of this test. |
| 71 | |
| 72 | **Stimulus**: Describe the stimulus procedure. |
| 73 | |
| 74 | **Check**: Describe the checking procedure.''' |
| 75 | |
| 76 | // Below is the list of written (runnable) tests that maps to `feature2`. |
| 77 | // To satisfactorilly test `feature2`, three tests are written. There |
| 78 | // could be various reasons to split the written test, the most common |
| 79 | // being unacceptably long runtime. |
| 80 | tests: ["foo_feature2_test1", |
| 81 | "foo_feature2_test2", |
| 82 | "foo_feature2_test3"] |
| 83 | } |
| 84 | ... |
| 85 | ] |
| 86 | ``` |
| 87 | |
| 88 | ### Covergroups |
| 89 | |
| 90 | A list of covergroups documented in the testplan represents the functional coverage plan for the design. |
| 91 | |
| 92 | The following attributes are used to define each covergroup: |
| 93 | * **name: name of the covergroup** |
| 94 | |
| 95 | This is a single `lower_snake_case` string that succinctly describes the covergroup. |
| 96 | It needs to map to the actual written covergroup, so that it can be audited from the simulation results for tracking. |
| 97 | As indicated in our DV style guide, the covergroup name is suffixed with `_cg`. |
| 98 | |
| 99 | * **desc: description of the covergroup** |
| 100 | |
| 101 | A multi-line string that briefly describes what functionality is captured by the covergroup. |
| 102 | It is recommended, but not necessary to list the individual coverpoints and crosses to ease the review. |
| 103 | |
| 104 | Covergroups are added to the testplan using the `covergroups` key. |
| 105 | Here's an example: |
| 106 | ```hjson |
| 107 | covergroups: [ |
| 108 | { |
| 109 | name: timer_cg |
| 110 | desc: '''Cover various combinations of rv_timer inputs when generating a |
| 111 | timeout. Cover appropriate ranges of values of step and prescaler |
| 112 | as coverpoint buckets and cross them with each other. |
| 113 | ''' |
| 114 | } |
| 115 | ... |
| 116 | ] |
| 117 | ``` |
| 118 | ### Import shared testplans |
| 119 | |
| 120 | Typically, there are tests that are common to more than one testbench and can be made a part of a 'shared' testplan that each DUT testplan can simply import. |
| 121 | An example of this is running the automated UVM RAL CSR tests, which applies to almost all DUTs. |
| 122 | This is achieved using the `import_testplans` key: |
| 123 | ```hjson |
| 124 | import_testplans: ["util/dvsim/examples/testplanner/common_testplan.hjson", |
| 125 | "hw/dv/tools/csr_testplan.hjson"] |
| 126 | ``` |
| 127 | |
| 128 | Note that the paths to common testplans are relative to `$REPO_TOP`. |
| 129 | |
| 130 | For the sake of discussion below, we will refer to the 'main' or DUT testplan as the 'DUT' testplan and the shared testplans it imports as 'shared' or 'imported' testplans. |
| 131 | |
| 132 | The imported testplans actually present a problem: how can the written tests that map to the shared testpoint be generic enough that they apply to multiple DUTs? |
| 133 | We currently solve this by providing substitution wildcards. |
| 134 | These are single `lower_snake_case` strings indicated within braces `'{..}'`. |
| 135 | A substitution value (or list of values) for the wildcard string is optionally provided in the DUT testplan. |
| 136 | |
| 137 | Here's an example: |
| 138 | ```hjson |
| 139 | ------- |
| 140 | // UART testplan: |
| 141 | name: uart |
| 142 | |
| 143 | ------- |
| 144 | // Imported testplan: |
| 145 | { |
| 146 | name: csr |
| 147 | ... |
| 148 | tests: ["{name}{intf}_csr_hw_reset"] |
| 149 | } |
| 150 | ``` |
| 151 | |
| 152 | In the example above, `{name}` and `{intf}` are wildcards used in the shared testplan for which substitution values are to be provided in the DUT testplan. |
| 153 | When the tool parses the DUT testplan along with its imported testplans, it replaces the wildcards with its substitution values found in the DUT testplan. |
| 154 | If a substitution is not available, the wildcard is replaced with an empty string. |
| 155 | In the example above, the list of written tests resolves to `["uart_csr_hw_reset"]` after substituting `{name}` with `uart` and `{intf}` with an empty string. |
| 156 | As many wildcards as needed can be added to tests in the shared testplans to support the various usecases across different testbenches. |
| 157 | Also, the substitution value can be a list of strings, in which case, the list of written tests expands to all possible combinations of values. |
| 158 | |
| 159 | Here's an example: |
| 160 | ```hjson |
| 161 | ------- |
| 162 | // Chip testplan: |
| 163 | name: chip |
| 164 | intf: ["", "_jtag"] |
| 165 | foo: ["x", "y", "z"] |
| 166 | |
| 167 | ------- |
| 168 | // Imported testplan: |
| 169 | { |
| 170 | name: csr |
| 171 | ... |
| 172 | tests: ["{name}{intf}_csr_hw_reset_{foo}"] |
| 173 | } |
| 174 | ``` |
| 175 | |
| 176 | This will resolve to the following 6 tests: |
| 177 | |
| 178 | ``` |
| 179 | ["chip_csr_hw_reset_x", "chip_csr_hw_reset_y", "chip_csr_hw_reset_z", |
| 180 | "chip_jtag_csr_hw_reset_x", "chip_jtag_csr_hw_reset_y", "chip_jtag_csr_hw_reset_z"] |
| 181 | ``` |
| 182 | |
| 183 | ### Example sources |
| 184 | |
| 185 | The following examples provided within `util/dvsim/examples/testplanner` can be used as a starting point. |
| 186 | * **`foo_testplan.hjson`**: DUT testplan |
| 187 | * **`common_testplan.hjson`**: shared testplan imported within the DUT testplan |
| 188 | * **`foo_dv_doc.md`**: DUT testplan imported within the DV document doc in Markdown |
| 189 | |
| 190 | In addition, see the [UART DV document]({{< relref "hw/ip/uart/doc/dv" >}}) for a 'production' example of inline expansion of an imported testplan as a table within the DV document. |
| 191 | The [UART testplan](https://github.com/lowRISC/opentitan/blob/master/hw/ip/uart/data/uart_testplan.hjson) imports some of the shared testplans located at `hw/dv/tools/dvsim/testplans` area. |
| 192 | |
| 193 | ### Limitations |
| 194 | |
| 195 | The following limitations currently hold: |
| 196 | * Only the DUT testplan can import shared testplans; the imported testplans cannot further import more testplans. |
| 197 | * All planned test names parsed from the DUT testplan and all of its imported testplans need to be unique. |
| 198 | |
| 199 | ## Usage examples |
| 200 | |
| 201 | ### Standalone tool invocations |
| 202 | |
| 203 | Generate the testplan table in HTML to stdout: |
| 204 | ```console |
| 205 | $ cd $REPO_TOP |
| 206 | $ ./util/dvsim/testplanner.py \ |
| 207 | util/dvsim/examples/testplanner/foo_testplan.hjson |
| 208 | ``` |
| 209 | |
| 210 | Generate the testplan table in HTML to a file: |
| 211 | ```console |
| 212 | $ ./util/dvsim/testplanner.py \ |
| 213 | util/dvsim/examples/testplanner/foo_testplan.hjson \ |
| 214 | -o /tmp/foo_testplan_table.html |
| 215 | ``` |
| 216 | |
| 217 | Generate simulation result tables in HTML to stdout: |
| 218 | ```console |
| 219 | $ ./util/dvsim/testplanner.py \ |
| 220 | util/dvsim/examples/testplanner/foo_testplan.hjson \ |
| 221 | -s util/dvsim/examples/testplanner/foo_sim_results.hjson |
| 222 | ``` |
| 223 | |
| 224 | Note that the simulations results HJson file used for mapping the results to the testplan is for illustration. |
| 225 | `dvsim` does not generate such a file - it invokes the `Testplan` class APIs directly to map the simulation results. |
| 226 | |
| 227 | Generate simulation result tables in HTML to a file: |
| 228 | ```console |
| 229 | $ ./util/dvsim/testplanner.py \ |
| 230 | util/dvsim/examples/testplanner/foo_testplan.hjson \ |
| 231 | -s util/dvsim/examples/testplanner/foo_sim_results.hjson \ |
| 232 | -o /tmp/foo_sim_results.html |
| 233 | ``` |
| 234 | |
| 235 | ### APIs for external tools |
| 236 | The `util/build_docs.py` script invokes the testplanner utility functions directly to parse the Hjson testplan and insert an HTML table within the DV document. |
| 237 | This is done by invoking: |
| 238 | ```console |
| 239 | $ ./util/build_docs.py --preview |
| 240 | ``` |
| 241 | The output for each testplan will be saved into `build/docs-generated`. |
| 242 | For example the GPIO IP testplan is rendered into a table at `build/docs-generated/hw/ip/gpio/data/gpio_testplan.hjson.testplan`. |
| 243 | The complete OpenTitan documentation is rendered locally at `https://localhost:1313`. |
| 244 | |
| 245 | The following snippet of code can be found in `util/build_docs.py`: |
| 246 | ```python |
| 247 | from dvsim.Testplan import Testplan |
| 248 | |
| 249 | # hjson_testplan_path: a string pointing to the path to Hjson testplan |
| 250 | testplan = Testplan(hjson_testplan_path) |
| 251 | text = testplan.get_testplan_table("html") |
| 252 | ``` |
| 253 | |
| 254 | ## Future work |
| 255 | * Allow DUT and its imported testplans to have the same testpoint name as long as they are in separate files. |
| 256 | * The list of written tests are appended from both files. |
| 257 | * The descriptions are merged - its upto the user to ensure that it is still meaningful after the merge. |
| 258 | * Conflicting milestones are flagged as an error. |