Today I was trying to Simulate an Optimized version of OpenRISC CPU at Gate level.

To Synthesize the core I had used one of the ASIC technology nodes that we have in the laboratory and I wanted to obtain estimates on power consumption of OpenRISC under different workloads.

Obviously, the best way to obtain the power consumption is to obtain circuit switching activity at Gate Level or RTL (refer to MiMAPT paper) and then to feed them to the tool for power estimation. In order to do that I had to perform a Post-synthesis or Post-route simulation on the OpenRISC but, there is a problem!

Usually, when you have the OpenRISC on FPGA, all of the registers are initialized by zero from the beginning. At gate-level simulation time, using the global set/reset signals, these registers are initialized to zero.

In the real ASIC, the synthesis tool tries to optimize the area, by removing the reset circuitry from those registers in the design and don’t really need reset signal at all. This is also true from memory elements inside the design.

However, this causes problems when you try to simulate the ASIC synthesized circuit. Those storage elements which are not reset in the initial phase of simulation will be simply considered as X by the simulator. These X values propagate through your circuit when the simulation progresses through time and this completely affects the result of your simulation.

Here is a solution, provided by Synopsys, to solve this problem for the Synopsys VCS.

This solution allows you to initialize all of the design registers to zero at the beginning of your post-synthesis or gate-level simulation.

Basically the solution consists of two steps:

  1. Inside Synopsys DC, when you have your design linked, synthesized and ready, you run a script which obtains a complete list of storage elements in your design.
  2. Inside Synopsys VCS before running the simulation, you use the generated list and reset all of the storage elements to a fixed value.

Here is the TCL script provided by Synopsys: find_force_registers

Inside DC, after you had your design synthesized and ready, you load the script and then you run it. Here is an example:


source find_force_registers.tcl

find_force_registers AXI_OpenRISC_testbench.AXI_OpenRISC_topIns force_regs.ucli 0 access.tab

The find_force_registers, receives 4 parameter. The first one is the instance name of your design.

For example, if the module name of your testbench is AXI_OpenRISC_testbench and then inside your testbench you have instantiated your RTL module with the instance name of AXI_OpenRISC_topIns , then the first parameter passed to find_force_registers should be : AXI_OpenRISC_testbench.AXI_OpenRISC_topIns.

The next parameter is the name of the file that you like the script to create and to put the VCS UCLI commands inside.

The third parameter is the value to which you want to initialize all registers.

The final file will contain a set of permission required at the time of initializing registers by VCS.

Now at VCS side, first, when you want to run VCS to compile your design, you add “-P access.tab” to the list of options passed to VCS. For example, this is the command I use to compile AXI OpenRISC:


vcs -debug -full64 -PP +v2k -timescale=1ns/1ps +neg_tchk -P access.tab \
../...LIST OF FILES \
../DC/AXI_OpenRISC_top_synthesized_mapped.v \
../simRTL/AXI_OpenRISC_testbench.v

Then when simv executable got created, you run it in UCLI mode:


./simv -ucli

Inside the UCLI environment, you run the created ucli script


source force_regs.ucli

and then you simply issue the run command to run the entire simulation.

Now you can look at the results of the simulation without being worried about the problem of X propagation.

However, if you are going to fabricate your chip, then you should be worried about what if this method has actually prevented you to discover the problems of your design with initialization and reset.