2. Getting Started

To build a core and to simulate it on a test-soc, you will need the following tools:

  1. Bluespec Compiler: This is required to compile the BSV based soc, core, and other devices to Verilog.

  2. Python3.7: Python 3.7 is required to configure compilation macros and clone dependencies.

  3. Verilator 4.106+: Verilator is required for simulation purposes.

  4. RISC-V Toolchain 9.2.0+: You will need to install the RISC-V GNU toolchain to be able to compile programs that can run on ChromiteM.

  1. RISC-V OpenOCD :This is required if you would like to simulate through GDB uding remote-bitbang for JTAG communication.


The user is advised to install the above tools from their respective repositories/sources.

You will need the following as well, the installation of which is presented below:

  1. Python 3.6.0+: see python

  2. DTC version 1.4.7+: see dtc

2.1. Install Dependencies

2.1.1. Python

Ubuntu 17.10 and 18.04 by default come with python-3.6.9 which is sufficient for using riscv-config.

If you are are Ubuntu 16.10 and 17.04 you can directly install python3.6 using the Universe repository

$ sudo apt-get install python3.6
$ pip3 install --upgrade pip

If you are using Ubuntu 14.04 or 16.04 you need to get python3.6 from a Personal Package Archive (PPA)

$ sudo add-apt-repository ppa:deadsnakes/ppa
$ sudo apt-get update
$ sudo apt-get install python3.6 -y
$ pip3 install --upgrade pip

You should now have 2 binaries: python3 and pip3 available in your $PATH. You can check the versions as below

$ python3 --version
Python 3.6.9
$ pip3 --version
pip 20.1 from <user-path>.local/lib/python3.6/site-packages/pip (python 3.6)

2.1.2. Install DTC (device tree compiler)

We use the DTC 1.4.7 to generate the device tree string in the boot-files. To install DTC follow the below commands:

sudo wget https://git.kernel.org/pub/scm/utils/dtc/dtc.git/snapshot/dtc-1.4.7.tar.gz
sudo tar -xvzf dtc-1.4.7.tar.gz
cd dtc-1.4.7/
sudo make NO_PYTHON=1 PREFIX=/usr/
sudo make install NO_PYTHON=1 PREFIX=/usr/

2.2. Building the Core

The code is hosted on Gitlab and can be checked out using the following command:

$ git clone https://gitlab.com/incoresemi/core-generators/chromite.git

If you are cloning the chromite repo for the first time it would be best to install the dependencies first:

$ cd chromite/
$ pyenv activate venv # ignore this is you are not using pyenv
$ pip install -U -r requirements.txt

The Chromite core generator takes a specific YAML format as input. It makes specific checks to validate if the user has entered valid data and none of the parameters conflict with each other. For e.g., mentioning the ‘D’ extension without the ‘F’ will get captured by the generator as an invalid spec. More information on the exact parameters and constraints on each field are discussed here.

Once the input YAML has been validated, the generator then clones all the dependent repositories which enable building a test-soc, simulating it and performing verification of the core. This is an alternative to maintaining the repositories as submodules, which typically pollutes the commit history with bump commits.

At the end, the generator outputs a single makefile.inc in the same folder that it was run, which contains definitions of paths where relevant bluespec files are present, bsc command with macro definitions, verilator simulation commands, etc.

A sample yaml input YAML (default.yaml) is available in the sample_config directory of the repository.

To build the core with a sample test-soc using the default config do the following:

$ python -m configure.main -ispec sample_config/rv64imacsu/isa.yaml
  -customspec sample_config/rv64imacsu/custom.yaml -cspec sample_config/rv64imacsu/core.yaml
  -gspec sample_config/rv64imacsu/csr_grouping.yaml
  -dspec sample_config/rv64imacsu/debug.yaml --verbose debug

The above step generates a makefile.inc file in the same folder and also clones other dependent repositories to build a test-soc and carry out verification. This should generate a log something similar to:

[INFO]    : ************ Chromite Core Generator ************
[INFO]    : ------ Copyright (c) InCore Semiconductors ------
[INFO]    : ---------- Available under BSD License----------
[INFO]    :

[INFO]    : Checking pre-requisites
[INFO]    : Cloning "cache_subsystem" from URL "https://gitlab.com/incoresemi/blocks/cache_subsystem"
[INFO]    : Checking out "1.0.0" for repo "cache_subsystem"
[INFO]    : Cloning "common_bsv" from URL "https://gitlab.com/incoresemi/blocks/common_bsv"
[INFO]    : Checking out "master" for repo "common_bsv"
[INFO]    : Cloning "fabrics" from URL "https://gitlab.com/incoresemi/blocks/fabrics"
[INFO]    : Checking out "1.1.1" for repo "fabrics"
[INFO]    : Cloning "bsvwrappers" from URL "https://gitlab.com/incoresemi/blocks/bsvwrappers"
[INFO]    : Checking out "master" for repo "bsvwrappers"
[INFO]    : Cloning "devices" from URL "https://gitlab.com/incoresemi/blocks/devices"
[INFO]    : Checking out "1.0.0" for repo "devices"
[INFO]    : Cloning "benchmarks" from URL "https://gitlab.com/incoresemi/core-generators/benchmarks"
[INFO]    : Checking out "master" for repo "benchmarks"
[INFO]    : Loading input file: /scratch/git-repo/incoresemi/core-generators/chromite/sample_config/default.yaml
[INFO]    : Load Schema configure/schema.yaml
[INFO]    : Initiating Validation
[INFO]    : No Syntax errors in Input Yaml.
[INFO]    : Performing Specific Checks
[INFO]    : Generating BSC compile options
[INFO]    : makefile.inc generated
[INFO]    : Creating Dependency graph
[WARNING] : path: .:%/Libraries:src/:src/predictors:src/m_ext:src/fpu/:src/m_ext/..........
defines: Addr_space=25 ASSERT rtldump RV64 ibuswidth=64 dbuswidth=64 .......
builddir: build/hw/intermediate
topfile: test_soc/TbSoc.bsv
outputfile: depends.mk
generated make dependency rules for "test_soc/TbSoc.bsv" in: depends.mk
[INFO]    : Dependency Graph Created
[INFO]    : Cleaning previously built code
[WARNING] : rm -rf build/hw/intermediate/* *.log bin/* obj_dir build/hw/verilog/*
rm -f *.jou rm *.log *.mem log sim_main.h cds.lib hdl.var
[INFO]    : Run make -j<jobs>

To compile the bluespec source and generate verilog

$ make -j<jobs> generate_verilog

If you are using the samples/default.yaml config file, this should generate the following folders:

  1. build/hw/verilog: contains the generated verilog files.

  2. build/hw/intermediate: contains all the intermediate and information files generated by bsc.

To create a verilated executable:

$ make link_verilator_elf

This will generate a bin folder containing the verilated chromite_core executable. This can be used for simulation as described in Section 2.3.

Congratulations - You have built your very first Chromite core !! :)

2.3. Simulating the Core

The Chromite repository also contains a simple test-soc for the purpose of simulating applications and verifying the core.

2.3.1. Structure of Test-SoC

The Test-SoC has the following structure (defined to a max of 5 levels of depth):

graph TD; X[mkTbSoC] --> A(mkSoC) X --> B(mkbram) X --> C(mkbootrom) A --> D(mkccore_axi4) A --> E(mkuart) A --> F(mkclint) A --> G(mksignature_dump) D --> H(mkriscv) D --> I(mkdmem) D --> J(mkimem) J --> K(mkicache) J --> L(mkitlb*) I --> M(mkdcache) I --> N(mkdtlb*)

Description of the above modules:




Contains the 6-stages of the core pipeline including the execution and only the interface to the memory subsystem


The Data memory subsystem. Includes the data-cache and data-tlbs


The instruction memory subsystem. Includes the instruction-cache and the instruction-tlbs


Contains the above modules and the integrations across them. Also provides 3 AXI-4 interfaces to be connected to the Cross-bar fabric


UART module


Core Level Interrupt


Signature dump module (for simulation only)


contains all the above modules and instantiates the AXI-4 crossbar fabric as well. The fabric has 2 additional slaves, which are brought out through the interface to connect to the boot-rom and bram-main-memory present in the Test-bench


BRAM based memory acting as main-memory


Bootrom slave


Testbench that instantiates the Soc, and integrates it with the bootrom and a bram memory

The details of the devices can be found in devices Address Map of Test SoC


Address Range


0x80000000 - 0x8FFFFFFF


0x00001000 - 0x00010FFF


0x00011300 - 0x00011340


0x02000000 - 0x020BFFFF

Debug-Halt Loop

0x00000000 - 0x0000000F

Signature Dump

0x00002000 - 0x0000200c

Please note that the bram-based memory in the test-bench can only hold upto 32MB of code. Thus the elf2hex arguments will need to applied accordingly.


The elf2hex program is available from the modified spike application.


The size of the BRAM Memory can be changed by changing the configuration bsc_compile_options.test_memory_size in the configuration YAML. BootRom Content

By default, on system-reset the core will always jump to 0x1000 which is mapped to the bootrom. The bootrom is initialized using the file boot.mem. The bootrom after a few instructions causes a re-direction jump to address 0x80000000 where the application program is expected to be. It is thus required that all programs are linked with text-section begining at 0x80000000. The rest of the boot-rom holds a dummy device-tree-string information.

To boot.mem file is generated in the bin folder using the following command:

$ make generate_boot_files


You can skip executing the bootrom by changing the reset_pc field in the configuration YAML. However, the verilated executable will still require a dummy boot.mem file to initiate simulation

2.3.2. Verilated Executable

We use verilator to simulate the core and the test-soc described above. In order to generate the verilated executable do the following (you can skip this is you have already followed the steps so far)

$ cd chromite
$ python -m configure.main -ispec sample_config/default.yaml
$ make -j<jobs> generate_verilog
$ make link_verilator_elf generate_boot_files

The above should result in following files in the bin folder:

  • chromite_core

  • boot.mem

2.3.3. Executing User Programs

Let’s assume the software program that you would like to simulate on the core is called prog.elf (compiled using standard riscv-gcc).

In order to run this elf on the chromite verilated executable you can do the following:

$ ./chromite_core +elf=<path to prog.elf>


Since the boot code in the bootrom implicitly jumps to 0x80000000 the programs should also be compiled at 0x80000000. Hello World

To run hello-world first ensure the verilated executable is available in the bin folder (use steps mentionedin in Section 2.3.2. After which run the following:

$ make hello
Hello World Dhrystone

To run dhrystone first ensure the verilated executable is available in the bin folder (use steps mentionedin in Section 2.3.2. After which run the following:

$ make dhrystone ITERATIONS=10000

Microseconds for one run through Dhrystone:     10.0
Dhrystones per Second:                       98448.0


The above numbers are obtained by using the samples/rv64imacsu/* config files which have been configured for high performance. The performance numbers will change based on the config used to generate the core instance. CoreMarks

To run coremarks first ensure the verilated executable is available in the bin folder (use steps mentionedin in Section 2.3.2. After which run the following:

$ make coremarks ITERATIONS=35

2K performance run parameters for coremark.
CoreMark Size    : 666
Total ticks      : 12323206
Total time (secs): 12
Iterations/Sec   : 2
Iterations       : 35
Compiler version : riscv64-unknown-elf-9.2.0
Compiler flags   : -mcmodel=medany -DCUSTOM -DPERFORMANCE_RUN=1 -DMAIN_HAS_NOARGC=1 \
                   -DITERATIONS=35 -O3 -fno-common -funroll-loops -finline-functions \
                   -fselective-scheduling -falign-functions=16 -falign-jumps=4 \
                   -falign-loops=4 -finline-limit=1000 -nostartfiles -nostdlib \
                   -ffast-math -fno-builtin-printf -march=rv64imafdc -mexplicit-relocs
Memory location  : STACK
seedcrc          : 0xe9f5
[0]crclist       : 0xe714
[0]crcmatrix     : 0x1fd7
[0]crcstate      : 0x8e3a
[0]crcfinal      : 0xcf56
Correct operation validated. See README.md for run and reporting rules.


The above numbers are obtained by using the samples/default.yaml config file which has been configured for high performance. The performance numbers will change based on the config used to generate the core instance.

2.3.4. Notes on Simulation Support for PutChar

The test-soc for simulation contains a simple uart. The putchar function for the same is available HERE. This has to be used in the printf functions. The output of the putchar is captured in a separate file app_log during simulation. Simulation Arguments (plusargs)

  1. ./chromite_core +elf=<elf-path> +rtldump: if the core has been configured with trace_dump: true , then a rtl.dump file is created which shows the log of instruction execution. Each line in the file has the following format:

    <privilege-mode> <program-counter> <instruction> <register-updated> <register value>
  2. To enable printing of debug statements from the bluespec code, one can pass custom logger arguments to the simulation binary as follows

    • ./chromite_core +elf=<elf-path> +fullverbose: prints all the logger statements across all modules and all levels of verbosity

    • ./chromite_core +elf=<elf-path> +mstage1 +l0: prints all the logger statements within module stage1 which are at verbosity level 0.

    • ./chromite_core +elf=<elf-path> +mstage2 +mstage4 +l0 +l3: prints all the logger statements within modules stage2 and stage4 which are at verbosity levels 0 and 3 only.

  3. To print the cycle difference between 2 consecutive instruction commits you can use

+instr_latency along with rtldump to appen this in the rtl.dump file itself.

  1. To exit the simulation when a self-loop is encountered use +halt_selfloop with the compiled binary

  2. An app_log file is also created which captures the output of the uart, typically used in the putchar function in C/C++ codes as mentioned above. Connect to GDB in Simulation

A debugger implementation following the riscv-debug-draft-014 has been integrated with the core. This can be instantiated in the design by configuring with: debugger_support: true

Perform the following steps to connect to the core executable with a gdb terminal. This assumes you have installed openocd and is available as part of you $PATH variable.

Modify the sample_config/default.yaml to enable: debugger_support and open_ocd. Generate a new executable with this config to support jtag remote-bitbang in the test-bench

$ python -m configure.main -ispec sample_config/default.yaml
$ make gdb # generate executable with open-ocd vpi enabled in the test-bench
  1. Simulate the RTL In a new terminal do the following:

    $ cd chromite/bin/
    $ ./chromite_core +elf=<elf-path> > /dev/null
  2. Connect to OpenOCD Open a new terminal and type the following:

    $ cd chromite/test_soc/gdb_setup/
    $ openocd -f shakti_ocd.cfg
  3. Connect to GDB Open yet another terminal and type the following:

    $ cd chromite/test_soc/gdb_setup
    $ riscv64-unknown-elf-gdb -x gdb.script

In this window you can now perform gdb commands like : set $pc, i r, etc

To reset the SoC via the debugger you can execute the following within the gdb shell:

$ monitor reset halt
$ monitor gdb_sync
$ stepi
$ i r


The above will not reset memories like the BRAM Memory.