|
1 | | -# Tywaves demo projec: Chisel backend |
2 | | -Demo backend of the Tywaves project. This repo contains function that parse the information a Chisel circuit, debug info emitted by the firtool compiler, simulate a circuit using ChiselSim and combine all the information to the [surfer-tywaves-demo](https://gitlab.com/rameloni/surfer-tywaves-demo) frontend (an extension of the Surfer waveform viewer written in Rust to support Chisel). |
| 1 | +# Tywaves demo project: Chisel backend |
| 2 | + |
| 3 | +Demo backend of the Tywaves project: a type based waveform viewer for Chisel |
| 4 | +and [Tydi-Chisel](https://github.com/abs-tudelft/Tydi-Chisel) circuits. |
| 5 | +This repo contains functions that parse the information of a Chisel circuit and the debug info emitted by the firtool |
| 6 | +compiler, simulate a circuit using ChiselSim and combine all the information to the |
| 7 | +[surfer-tywaves-demo](https://gitlab.com/rameloni/surfer-tywaves-demo) frontend (an extension of the Surfer waveform |
| 8 | +viewer written in Rust to support Chisel constructs). |
| 9 | + |
| 10 | +Since it is a demo project, it has been tested and developed for a restricted set of examples (it may not work with |
| 11 | +all circuits). In the [features](#features) section, you can find the already supported features. |
| 12 | + |
| 13 | +Starting from this demo project, a better implementation and integration in the Chisel/Firrtl infrastructure will be |
| 14 | +developed that aims to address the issues |
| 15 | +discovered [here](https://github.com/rameloni/Tydi-Chisel-testing-frameworks-analysis). |
| 16 | + |
| 17 | +> Do not use Verilog / System Verilog reserved keywords in Chisel circuit (i.e. `wire`, `reg`). |
| 18 | +> In that case, `firtool` will change the `var_name` (which should be `wire`) field of the emitted HGLDD to get a legal |
| 19 | +> name as explained in the comments |
| 20 | +> [here](https://github.com/llvm/circt/blob/37fbe5e5f5c7a07064d02cea8bf4e8454178fc0e/lib/Target/DebugInfo/EmitHGLDD.cpp#L163C1-L175C2). |
| 21 | +> Thus, it is not possible to match Chisel/FIRRTL with the `var_name` in HGLDD. |
| 22 | +> |
| 23 | +> HGLDD is a file format emitted for other existing tools based on verilog simulations and verilog keywords. |
| 24 | +> **I am using it temporarily and in the future firtool will be able to emit a new file format more consistent with |
| 25 | +> tywaves.** |
| 26 | +
|
| 27 | +# Table of contents |
| 28 | + |
| 29 | +- [Installation](#installation) |
| 30 | + - [Install surfer-tywaves-demo](#install-surfer-tywaves-demo) |
| 31 | + - [Publish locally this scala project](#publish-locally-this-scala-project) |
| 32 | +- [Use it on your project](#use-it-on-your-project) |
| 33 | +- [Example output](#example-output) |
| 34 | +- [Features](#features) |
| 35 | +- [How it works internally](#how-it-works-internally) |
| 36 | + - [Drawbacks](#drawbacks) |
| 37 | + |
| 38 | +# Installation |
| 39 | + |
| 40 | +You can run `make all` to install all the pre-requisites. |
| 41 | + |
| 42 | +## Install [surfer-tywaves-demo](https://gitlab.com/rameloni/surfer-tywaves-demo/-/tree/tywaves) |
| 43 | + |
| 44 | +The makefile contains a rule to clone the frontend repository, build and install it. |
| 45 | + |
| 46 | +```bash |
| 47 | +make install-surfer-tywaves |
| 48 | +make clean # To remove the cloned repository |
| 49 | +``` |
| 50 | + |
| 51 | +The frontend will be installed as `surfer-tywaves` executable. |
| 52 | + |
| 53 | +## Publish locally this scala project |
| 54 | + |
| 55 | +```bash |
| 56 | +make install-tywaves-backend |
| 57 | +``` |
| 58 | + |
| 59 | +Once published locally, the `tywaves-demo-backend` can be used by adding the following line to the `build.sbt` file: |
| 60 | + |
| 61 | +```scala |
| 62 | +libraryDependencies += "com.github.rameloni" %% "tywaves-backend" % "0.1.0-SNAPSHOT" |
| 63 | +``` |
| 64 | + |
| 65 | +# Use it on your project |
| 66 | + |
| 67 | +The `TywavesBackend` provides a [simulator](./src/main/tywaves/simulator/BetterEphemeralSimulator.scala) with |
| 68 | +functionalities to simulate a circuit through [svsim](https://github.com/chipsalliance/chisel/tree/main/svsim), emit VCD |
| 69 | +traces and of course generate the symbol table for the waveform viewer itself automatically. |
| 70 | + |
| 71 | +The following example shows how it is possible also to: |
| 72 | + |
| 73 | +- Enable the trace of the simulation |
| 74 | +- Launch the waveform viewer after the simulation |
| 75 | +- Set the name of the simulation (it will be used to create a folder with a user defined name for the traces and |
| 76 | + workspace of svsim) |
| 77 | +- Use tywaves and expect API to test the circuit |
| 78 | + |
| 79 | +```scala |
| 80 | +import tywaves.simulator.BetterEphemeralSimulator._ |
| 81 | +import tywaves.simulator.simSettings |
| 82 | +import org.scalatest.flatspec.AnyFlatSpec |
| 83 | + |
| 84 | +class BarTest extends AnyFlatSpec { |
| 85 | + behavior of "BarTest" |
| 86 | + it should "trace simple bar" in { |
| 87 | + simulate( |
| 88 | + new Bar, |
| 89 | + Seq(simSettings.EnableTraceWithUnderscore, simSettings.LaunchTywavesWaveforms), |
| 90 | + simName = "trace_simple_bar", |
| 91 | + ) { c => |
| 92 | + c.io.a.poke(true) |
| 93 | + c.io.b.poke(false) |
| 94 | + c.io.out.expect(false.B) |
| 95 | + c.clock.step() |
| 96 | + c.io.a.poke(true) |
| 97 | + c.io.b.poke(true) |
| 98 | + c.io.out.expect(true.B) |
| 99 | + c.clock.step() |
| 100 | + } |
| 101 | + } |
| 102 | +} |
| 103 | +``` |
| 104 | + |
| 105 | +# Example output |
| 106 | + |
| 107 | +The following images show the classic and tywaves waveform visualization of the [GCD](./src/test/gcd/GCD.scala) module. |
| 108 | +It is possible to see that the left picture does not provide any information about Chisel level types and hierarchy. |
| 109 | + |
| 110 | +```scala |
| 111 | +class GCD extends Module { |
| 112 | + val io = IO(new Bundle { |
| 113 | + val a = Input(UInt(32.W)) |
| 114 | + val b = Input(UInt(32.W)) |
| 115 | + val loadValues = Input(Bool()) |
| 116 | + val result = Output(UInt(32.W)) |
| 117 | + val resultIsValid = Output(Bool()) |
| 118 | + }) |
| 119 | + |
| 120 | + val x = Reg(UInt(32.W)) |
| 121 | + val y = Reg(UInt(32.W)) |
| 122 | + |
| 123 | + when(x > y)(x := x -% y).otherwise(y := y -% x) |
| 124 | + when(io.loadValues) { |
| 125 | + x := io.a; |
| 126 | + y := io.b |
| 127 | + } |
| 128 | + io.result := x |
| 129 | + io.resultIsValid := y === 0.U |
| 130 | +} |
| 131 | +``` |
| 132 | + |
| 133 | +| Only VCD loaded | Tywaves (VCD + symbol table) | |
| 134 | +|----------------------------------------------------|-------------------------------------------------------------| |
| 135 | +|  |  | |
| 136 | + |
| 137 | +# Features |
| 138 | + |
| 139 | +- [x] Parse and map Chisel/FIRRTL/Verilog circuits |
| 140 | +- [x] Emit VCD traces from the simulator (both with and without underscores in the signal names) |
| 141 | +- [x] |
| 142 | +- [x] Automatically generate the symbol table for the waveform viewer |
| 143 | + - [x] Dump Chisel types in the final symbol table |
| 144 | + - [x] Represent hierarchical structures of bundles |
| 145 | + - [ ] Represent vectors |
| 146 | + - [ ] Represent enums |
| 147 | + - [ ] Represent hierarchical modules |
| 148 | + - [ ] For loops code generation |
| 149 | + - [ ] Reg with init |
| 150 | + |
| 151 | +# How it works internally |
| 152 | + |
| 153 | +The following diagram shows the main components of the demo project and how they interact with each other. |
| 154 | + |
| 155 | + |
| 156 | +It retrieves, parses and finally maps together the Intermediate Representation (IR) of the Chisel, Firrtl and debug info |
| 157 | +emitted by the firtool (HGLDD) to output a symbol table that can be used by the frontend to display the waveform. |
| 158 | +It aims to map each high level signal (Chisel) to the low level signal (System Verilog) and vice versa. Usually, HGLDD |
| 159 | +would be enough, but it does provide only information about FIRRTL-to-SystemVerilog mapping, so it does not contain user |
| 160 | +types information. |
| 161 | + |
| 162 | +In this small example if I use only HGLDD I would be able to see that they are both bundles, but it is not possible to |
| 163 | +see that they are actually `MyFloat` and `IntCoordination` respectively. Also `Bool`, `UInt`, `SInt` would not be |
| 164 | +retrieved from HGLDD/FIRRTL only. From here the reason to use Chisel IR to get the user types information. |
| 165 | + |
| 166 | +```scala |
| 167 | +class MyFloat extends Bundle { |
| 168 | + val sign = Bool() |
| 169 | + val exponent = UInt(8.W) |
| 170 | + val significand = UInt(23.W) |
| 171 | +} |
| 172 | + |
| 173 | +class IntCoordination extends Bundle { |
| 174 | + val x = SInt(32.W) |
| 175 | + val y = SInt(32.W) |
| 176 | +} |
| 177 | +``` |
| 178 | + |
| 179 | +## Drawbacks |
| 180 | + |
| 181 | +Chisel IR is an **internal** IR, and it is not meant to be used by external tools. It is not stable, and it can change |
| 182 | +basing on additional future features. It will be really hard to maintain this project for future Chisel versions. |
| 183 | +Therefore, I planned to "integrate" a functionality to directly transfer Chisel information to FIRRTL. In this way, |
| 184 | +the `firtool` would be able to access all the needed information for `surfer-tywaves-demo` to render the signals. |
| 185 | +This would also allow to simplify the process that `tywaves-demo-backend` currently does to generate the symbol table, |
| 186 | +improving performances. And it may extend the support to other languages/dialects in |
| 187 | +the [CIRCT](https://circt.llvm.org/) ecosystem. |
0 commit comments