ibex/vendor/lowrisc_ip/lint/doc/README.md
Philipp Wagner 8b42024cd5 Use vendored-in primitives from OpenTitan
Instead of using copies of primitives from OpenTitan, vendor the files
in directly from OpenTitan, and use them.

Benefits:

- Less potential for diverging code between OpenTitan and Ibex, causing
  problems when importing Ibex into OT.

- Use of the abstract primitives instead of the generic ones. The
  abstract primitives are replaced during synthesis time with
  target-dependent implementations. For simulation, nothing changes. For
  synthesis for a given target technology (e.g. a specific ASIC or FPGA
  technology), the primitives system can be instructed to choose
  optimized versions (if available).

  This is most relevant for the icache, which hard-coded the generic
  SRAM primitive before. This primitive is always implemented as
  registers. By using the abstract primitive (prim_ram_1p) instead, the
  RAMs can be replaced with memory-compiler-generated ones if necessary.

There are no real draw-backs, but a couple points to be aware of:

- Our ram_1p and ram_2p implementations are kept as wrapper around the
  primitives, since their interface deviates slightly from the one in
  prim_ram*. This also includes a rather unfortunate naming confusion
  around rvalid, which means "read data valid" in the OpenTitan advanced
  RAM primitives (prim_ram_1p_adv for example), but means "ack" in
  PULP-derived IP and in our bus implementation.

- The core_ibex UVM DV doesn't use FuseSoC to generate its file list,
  but uses a hard-coded list in `ibex_files.f` instead. Since the
  dynamic primitives system requires the use of FuseSoC we need to
  provide a stop-gap until this file is removed. Issue #893 tracks
  progress on that.

- Dynamic primitives depend no a not-yet-merged feature of FuseSoC
  (https://github.com/olofk/fusesoc/pull/391). We depend on the same
  functionality in OpenTitan and have instructed users to use a patched
  branch of FuseSoC for a long time through `python-requirements.txt`,
  so no action is needed for users which are either successfully
  interacting with the OpenTitan source code, or have followed our
  instructions. All other users will see a reasonably descriptive error
  message during a FuseSoC run.

- This commit is massive, but there are no good ways to split it into
  bisectable, yet small, chunks. I'm sorry. Reviewers can safely ignore
  all code in `vendor/lowrisc_ip`, it's an import from OpenTitan.

- The check_tool_requirements tooling isn't easily vendor-able from
  OpenTitan at the moment. I've filed
  https://github.com/lowRISC/opentitan/issues/2309 to get that sorted.

- The LFSR primitive doesn't have a own core file, forcing us to include
  the catch-all `lowrisc:prim:all` core. I've filed
  https://github.com/lowRISC/opentitan/issues/2310 to get that sorted.
2020-05-27 10:23:15 +01:00

6.6 KiB

RTL Linting

Linting is a productivity tool for designers to quickly find typos and bugs at the time when the RTL is written. Running lint is important when using SystemVerilog, a weakly-typed language, unlike other hardware description languages. We consider linting to be critical for conformance to our goals of high quality designs.

We have standardized on the AscentLint tool from RealIntent for this task due to its fast run-times and comprehensive set of rules that provide concise error and warning messages.

The lint flow leverages a new lint rule policy named "lowRISC Lint Rules" that has been tailored towards our Verilog Style Guide. The lint flow run scripts and waiver files are available in the GitHub repository of this project, but due to the proprietary nature of the lint rules and their configuration, the "lowRISC Lint Rules" lint policy file can not be publicly provided. However, the "lowRISC Lint Rules" are available as part of the default policies in AscentLint release 2019.A.p3 or newer (as LRLR-v1.0.policy). This enables designers that have access to this tool to run the lint flow provided locally on their premises.

Our linting flow leverages FuseSoC to resolve dependencies, build file lists and call the linting tools. See here for an introduction to this opensource package manager and here for installation instructions.

In order to run lint on a comportable IP block, the corresponding FuseSoC core file must have a lint target and include (optional) waiver files as shown in the following example taken from the FuseSoC core of the AES comportable IP:

filesets:

  [...]

  files_verilator_waiver:
    depend:
      # common waivers
      - lowrisc:lint:common
      - lowrisc:lint:comportable
    files:
      - lint/aes.vlt
    file_type: vlt

  files_ascentlint_waiver:
    depend:
      # common waivers
      - lowrisc:lint:common
      - lowrisc:lint:comportable
    files:
      - lint/aes.waiver
    file_type: waiver

  files_veriblelint_waiver:
    depend:
      # common waivers
      - lowrisc:lint:common
      - lowrisc:lint:comportable
  [...]

targets:
  default: &default_target
    filesets:
      - tool_verilator   ? (files_verilator_waiver)
      - tool_ascentlint  ? (files_ascentlint_waiver)
      - tool_veriblelint ? (files_veriblelint_waiver)
      - files_rtl
    toplevel: aes

  lint:
    <<: *default_target
    default_tool: verilator
    parameters:
      - SYNTHESIS=true
    tools:
      verilator:
        mode: lint-only
        verilator_options:
          - "-Wall"

Note that the setup shown above also supports RTL style linting with the open source tool Verible and RTL linting with Verilator in order to complement the sign-off lint flow with AscentLint. In particular, Verible lint focuses on different aspects of the code, and detects style elements that are in violation with our Verilog Style Guide.

The same lint target is reused for all three tools (we override the tool selection when invoking FuseSoC). Lint waivers can be added to the flow by placing them in the corresponding waiver file. In this example this would be lint/aes.waiver for AscentLint and lint/aes.vlt for Verilator.

In order to manually run lint on a specific block, make sure AscentLint is properly installed and step into the hw/lint folder. The makefile in that folder contains all targets that can be manually invoked. For example, to run lint on AES, do:

make ip-aes_lint

This run will exit with PASSED status on the command line if there are no lint errors or warnings. Otherwise it will exit with ERROR status, in which case you can get more information by running

make clean
make ip-aes_lint
make report

In order to build all lint targets and produce a summary report, the make all target can be invoked. For more detailed information on a particular lint run you can inspect the tool output inside the build folder that is created by FuseSoC.

Note that all AscentLint targets have a Verilator and Verible counterparts that are suffixed with _vlint and _slint, respectively. This enables designers without access to AscentLint to iterate with open-source tools before making their first Pull Request.

For batch regressions we have integrated this flow into the dvsim tool, which can be invoked as follows from the root of the project repository:

util/dvsim.py hw/top_earlgrey/lint/ascentlint/top_earlgrey_lint_cfgs.hjson --tool "ascentlint" --purge -mp 1

where the top_earlgrey_lint_cfgs.hjson file contains all the lint targets to be run in that regression (currently all available comportable IPs and the top-level are run). The purge option ensures that the scratch directory is fully erased before starting the build, and mp 1 sets the number of parallel workers to one (should be set depending on your licensing situation).

The batch regression is regularly run on the master branch at eight-hour intervals, and the results are published on a public dashboard such that everybody can inspect the current lint status of all IPs on the project website. The dashboard can be found by following the appropriate link on the hardware IP overview page.

CDC Linting

Logic designs that have signals that cross from one clock domain to another unrelated clock domain are notorious for introducing hard to debug problems. The reason is that design verification, with its constant and idealized timing relationships on signals, does not represent the variability and uncertainty of real world systems. For this reason, maintaining a robust Clock Domain Crossing verification strategy ("CDC methodology") is critical to the success of any multi-clock design.

Currently, due to the proprietary nature of tool collateral, all CDC linting activity is done offline and reported back to designers. The project will standardize on a particular CDC linting tool, and results will be shared in some form through continuous integration build results, published tool outputs, pre-submit checks, and/or linting summaries of tool output (TODO: publication details). At that time this README will be updated with setup and run instructions.

This holds for Reset Domain Crossing ("RDC") methodology as well.