Rocket Chip Documentation

repository·master·Indexed 26 days ago

https://github.com/chipsalliance/rocket-chip

A Scala-based generator using the Chisel hardware construction language to instantiate the RISC-V Rocket Core and complete SoC designs. Includes documentation on the Diplomacy parameter negotiation framework, LazyModule patterns, AXI4 interface definitions (AXI4Bundle, AXI4AsyncBundle, AXI4CreditedBundle), and the Debug Module Interface (DMI) protocol.

Tokens
9.3K
Snippets
22
Records
54
Agent score
87%

What's inside Rocket Chip

  1. Understand Diplomacy parameter negotiation

    master
    Diplomacy is a parameter negotiation framework used in Rocket Chip to generate parameterized protocol implementations. It allows different components of a hardware design to negotiate parameters (such as bus widths, address maps, or protocol features) before the final hardware structure is instantiated. This walkthrough demonstrates these concepts by building a simple parameterized adder.
  2. Connect Diplomacy nodes using binding operators

    master

    To complete a Diplomacy graph, you must bind nodes together in a top-level module (often a LazyModule acting as a testbench). The most common binding operator is :=.

    • Directionality: Sinks are typically placed on the left-hand side, and sources on the right-hand side (e.g., sinkNode := sourceNode).
    • Binding multiple nodes: You can iterate through sequences of nodes to establish multiple connections between modules.
  3. Configure IDE support (IntelliJ and VSCode) using Mill and Nix

    master

    Rocket Chip uses mill as its build tool and nix to configure the development environment. Follow these steps to enable language server support in your IDE.

    1. Install nix for your OS.
    2. Generate the BSP configuration:
      mill mill.bsp.BSP/install
    3. Patch the .bsp/mill-bsp.json file. Change the argv array to use nix develop so the IDE runs Mill within the Nix environment.

    For IntelliJ:

    • Install the Scala plugin.
    • If BSP doesn't run automatically, click bsp in the right sidebar and right-click your project to reload.

    For VSCode:

  4. Update Rocket Chip and Submodules

    master

    To keep your local repository up-to-date with the upstream master branch, pull the latest changes and recursively update the submodules.

    If the rocket-tools version has changed, you must recompile and install it by running the build scripts within the rocket-tools directory.

  5. Generate documentation using mdoc

    master

    The documentation in this repository is partially generated from source files using mdoc. To generate the documentation, ensure you are in the repository's root directory and run the docs/mdoc command from SBT.

    The resulting documentation will be output to the generated folder.

  6. Use the Rocket Chip Select library for LazyModules

    master
    While Chisel provides a Select library for finding hardware nodes, it can be fragile when used with Diplomacy because Diplomacy abstracts away much of the underlying Chisel hardware. Rocket Chip provides its own Select library designed specifically to operate on LazyModules and Nodes instead of Modules and Wires. This library allows you to traverse and query the hierarchy of your Diplomacy design.
  7. Define hardware using LazyModule and LazyModuleImp

    master

    Because Diplomacy performs parameter negotiation lazily after the graph is constructed, hardware must be defined using the LazyModule pattern:

    1. Extend LazyModule to define the module structure and its Diplomacy nodes.
    2. Define the actual Chisel hardware inside a lazy val module = new LazyModuleImp(this) { ... } block.
    3. Inside LazyModuleImp, you can access negotiated parameters via the nodes (e.g., node.in or node.out) to parameterize Chisel wires, bundles, and logic.
    class Adder(implicit p: Parameters) extends LazyModule {
      val node = new AdderNode(...) // Define node here
    
      lazy val module = new LazyModuleImp(this) {
        require(node.in.size >= 2)
        node.out.head._1 := node.in.unzip._1.reduce(_ + _)
      }
    
      override lazy val desiredName = "Adder"
    }
  8. Install and Checkout Rocket Chip

    master

    To use the Rocket Chip generator, clone the repository and initialize the required Git submodules.

    Note: You must also install dependencies for rocket-tools (see its specific README) and chisel3 (see Chisel3 installation guides) to ensure a functional environment.

    $ git clone https://github.com/ucb-bar/rocket-chip.git
    $ cd rocket-chip
    $ git submodule update --init
  9. Add external interrupts using HasAsyncExtInterrupts or HasSyncExtInterrupts

    master

    To add externally driven interrupts to a BaseSubsystem, use one of the following synchronization traits. Do not use HasExtInterrupts directly.

    • HasAsyncExtInterrupts: Use this if the external interrupts have NOT yet been synchronized to the Periphery (PLIC) clock. It automatically wires extInterrupts to ibus.fromAsync.
    • HasSyncExtInterrupts: Use this if the external interrupts have ALREADY been synchronized to the Periphery (PLIC) clock. It automatically wires extInterrupts to ibus.fromSync.
  10. Force invalidating the riscv-tools or Verilator caches

    master

    Rocket Chip uses GitHub Actions caching for riscv-tools and Verilator. While caches are automatically invalidated when riscv-tools.hash or verilator.hash changes, you can manually force an invalidation by incrementing the version number in the cache key within the workflow configuration.

    To invalidate a cache:

    1. Open .github/workflows/continuous-integration.yml.
    2. Find the job (e.g., prepare-riscv-tools-cache) containing the actions/cache@* step.
    3. Locate the key property. The key ends with a version suffix like -v1.
    4. Increment this number (e.g., change -v1 to -v2).
    5. Crucially, find all other occurrences of that specific cache key within the same file and increment them to match the new version number.
    6. Commit and push the changes to trigger a new cache build.
  11. Select nodes based on connectivity using Select.collectInwardEdges and Select.collectOutwardEdges

    master

    You can select LazyModules based on how they are connected in the design.

    • Select.collectInwardEdges(node)(partialFunction): Applies the partial function to all InwardEdges of the specified BaseNode.
    • Select.collectOutwardEdges(node)(partialFunction): Applies the partial function to all OutwardEdges of the specified BaseNode.

    Note: LazyModules also provide a getNodes method which returns all nodes instantiated within that module. This is often used in conjunction with the Select edge collectors to find connected modules.

    // Find all Leaf modules in 'top' that are connected to an 'A' module 
    // and do not belong to the 'foo:Foo' subhierarchy.
    Select.filterCollectDeep (top) {
      case _: Foo => false
      case _ => true
    } {
      case a: A =>
        // Function.unlift used to convert `InwardEdge => Option[String]` to `PartialFunction[InwardEdge, String]`
        a.getNodes.flatMap(Select.collectInwardEdges(_)(Function.unlift { edge =>
          edge.node.lazyModule match {
            case l: Leaf => Some(l.pathName)
            case _ => None
          }
        }))
    }