Hoang Trong Thuc - UEC & AIST, Tokyo, Japan


Understanding SiFive Freedom U540 Code Structure

I. Introduction

Reference link for SiFive Freedom:

I. a) Important files

They have two main series of CPU called E300 (rv32gc) and U500 (rv64gc). The way they structured them are similar. They used three kind of scala files, i.e., Shell file, Configs file, and Design file, to create a system.

File Description Example file
Configs file Is used as a configuration file for the CPU, and it's usually fixed for multiple designs. src/main/scala/unleashed/ DevKitConfigs.scala
Design file Is an extension upon the Configs file. In the Design file, all of the modules are called and connected. The Design file is also usually fixed for multiple platforms. src/main/scala/unleashed/ DevKitFPGADesign.scala
Shell file Is like a top file where all of the IOs are declared. They usually have one Shell file for each platform. fpga-shells/src/main/ scala/shell/xilinx/ VC707NewShell.scala

I. b) Build procedure

1: from Makefile -> to sbt

When ‘make verilog’ in the freedom top folder, the job of the Makefiles is just to pass the arguments into the sbt tool.

2: sbt: from .scala -> to .fir

The sbt tool is a tool to compile the scala codes into java executable files. Then, subsequently, create the .fir files from those java executives.

The actual command to create .fir file from scala codes:

java -jar $(rocketchip_dir)/sbt-launch.jar ++2.12.4 "runMain freechips.rocketchip.system.Generator $(BUILD_DIR) $(PROJECT) $(MODEL) $(CONFIG_PROJECT) $(CONFIG)"


3: from .fir -> to .v

After we have the .fir file, this is the command to create the verilog codes from the .fir file: (the verilog codes are generated into just one .v file)

java -Xmx2G -Xss8M -XX:MaxPermSize=256M -cp $(FIRRTL_JAR) firrtl.Driver -i <path to .fir file> -o <path to .v file> -X verilog

where $(FIRRTL_JAR) is the path that point to $(rocketchip_dir)/firrtl/utils/bin/firrtl.jar

I. c) Some concepts in SiFive codes

(i) Overlay

(ii) Source vs Sink

(iii) sbus vs mbus vs pbus

II. Shell File

This file is like a top file with the main purpose of IOs declaration.

This file doesn’t call the Design file or Config file. When ‘make’ by the sbt, this file and the Design file are called together by a single sbt command-line. The Shell file and the Design file ‘talk’ with each other by Overlays.

SiFive Freedom codes are relied on extending the LazyModule which relied on lazy val declaration. Because of the lazy property, if a group of IOs isn’t declared in the top Shell, the corresponding lazy module won’t be instantiated, thus leading to the removal of the relevant modules in the actual implementation.

For example: in the fpga-shells/src/main/scala/shell/xilinx/VC707NewShell.scala

abstract class VC707Shell()(implicit p: Parameters) extends Series7Shell
  . . .
  val led       = Overlay(LEDOverlayKey)       (new LEDVC707Overlay     (_, _, _))
  val switch    = Overlay(SwitchOverlayKey)    (new SwitchVC707Overlay  (_, _, _))
  . . .

If we just // the val led and val switch, like this:

abstract class VC707Shell()(implicit p: Parameters) extends Series7Shell
  . . .
  //val led       = Overlay(LEDOverlayKey)       (new LEDVC707Overlay     (_, _, _))
  //val switch    = Overlay(SwitchOverlayKey)    (new SwitchVC707Overlay  (_, _, _))
  . . .

Then the IOs of leds & switches won’t be declared, thus the GPIOs module won’t be instantiated in the design, and there will be no GPIOs module in the final verilog code.

III. Configs File

This file is the configuration file for the CPUs and internal bus systems.

This file is later called by the Design file.

IV. Design File

This file carries out the actual implementation of the design, with all of the modules and how they are connected.

This file calls and extends (or even overrides) the Configs file.