GSoC23 — Workweek 14


Hello everybody!

The PR implementing interconnection delays for input/output vectors has been merged! #994

This means that SDF INTERCONNECT support in Icarus Verilog is slowly, but surely becoming actually useful. What better way to celebrate this occasion than to simulate something big? Let's say a RISC-V CPU - the PicoRV32 in default configuration.

Simulating a RISC-V CPU with interconnection delays

I chose the PicoRV32 because it is a well designed CPU written in Verilog and I had already prior experience with it. By default it is configured as RV32I but can be adapted to support various requirements. It is optimized for size and fmax, so expect high frequencies.

First we need to generate the hard macro of the design via OpenLane. This will generate the layout for the CPU, but it will also create many other files that we need for the simulation, especially the gate-level netlist (GL) and the corresponding standard delay file (SDF).

I hardened the CPU several times to find the frequency where the timing is just right. We make use of this later to prove that the interconnection delays have an impact on the simulation.

Macro of PicoRV32

  • PDK: SKY130B
  • Stdcell library: sky130_fd_sc_hd
  • Area: 500um by 500um
  • Target density: 0.45
  • Clock period: 3ns

The PDK used for the design is SKY130B and the standard cell library is sky130_fd_sc_hd. The size was chosen as 500um by 500um. The target density is 0.45. The clock period is 3ns, resulting in a frequency of ~333MHz - not bad!

The next step is to gather all the necessary files for simulation. I have uploaded the GL, SDF and testbench to the interconnect-test repository and created a new Makefile target check_picorv32_example.

This target runs the simulation with both -gspecify and -ginterconnect enabled and annotates delays with the SDF file. Inside the testbench the CPU is connected to a small memory containing a simple program.

Since the CPU was hardened for a clock period of 3ns, everything should go well for a simulation using this clock period. And as expected, the output of the testbench, which is triggered by a write of the CPU to a special memory location, is as follows:

  Starting simulation...
  Hello World!
  Ending simulation...
  picorv32_example/top.v:135: $finish called at 10050000 (1ps)

( The "Hello World!" part is from the CPU)

The simulation time was 4m29.271s on my PC with an AMD Ryzen 7 1700X.

Increase the frequency!

Now let's increase the clock frequency to a value for which the CPU wasn't hardened for. I found that a period of 2.5ns and thus a frequency of 400MHz is just at the tipping point.

Two things may happen:

  1. Either the CPU fails so badly that we see no output at all because it never writes to the special memory location.
  2. Or the CPU fails in such a way that we get garbled output.

The simulation output with the higher clock frequency is as follows:

Starting simulation...
Hello$Wovld%woLello$Wovld%woLello$Wovld%Ending simulation...
picorv32_example/top.v:135: $finish called at 10050000 (1ps)

Well, that's a different "Hello World" for a change. I am happy to report that the second possibility has occurred ;)

But I haven't even told you the best part yet: If I disable interconnection delays via -gno-interconnect at the same clock frequency, I get a nice and clean Hello World! again. This means that only the interconnection delays are enough to tip the CPU over.

Side note: If timing checks were implemented in Icarus Verilog, the CPU would fail at an even lower clock frequency, since the setup and hold timings would be violated. So this simulation does not show what can happen in reality - that is unpredictable - but really that interconnection delays have an impact on the simulation and therefore are important to consider.

Let's talk about correctness

Now who says that all 21772 interconnection delays within the RISC-V CPU were correctly annotated and simulated? Checking them all by hand would take too long...

This is where my script comes in, which is automatically invoked by make check_picorv32_example. It compares all interconnect signal transition delays from the .vcd file with the ones specified in the SDF file.

║           Simulation Summary              ║
║ VCD File: picorv32_example.vcd            ║
║ SDF File: picorv32.sdf                    ║
║ Instance: top.picorv32_example_inst       ║
║  Number of Interconnects: 21772           ║
║  ✅ Number of Successes:  21772           ║
║  ❌ Number of Failures:   0               ║
║  Success Ratio            100.00 %        ║

Well, it seems to be alright ;)

I have also made a cross check with interconnection delays disabled.

Just to be clear there are still some issues and there is room for future improvements. For example there are some output ports that are not annotated correctly, but as these outputs are not used anyways (maybe that's where I should start looking?) they do not have an influence on the results. Also unused outputs must be at least connected to a wire so that the output ports are generated.


I think this blog post has shown very well the capabilities of SDF INTERCONNECT support in Icarus Verilog. Improvements may be made in the near future, but what is already there is enough to correctly simulate interconnection delays of a RISC-V CPU.

The last work week is approaching and in this one I will continue my work on the first timing check in Icarus Verilog.

Let's see how far I will get!