Skip to main content

Procedure

Debug Mode

There are certain aspects of writing new components from which you will benefit from the gem5 debug mode. I will cover some of those later, and I will make a note of when debug-specific features are used, but just keep that in mind. If you want to compile gem5 in debug mode, you can follow the installation instructions but replace your scons command with the following:

scons build/riscv/gem5.debug

You can find more information about other ways to build gem5 on the learning gem5 website.

When creating a new object in gem5, there are generally three steps:

  1. Register the component for compilation with gem5
  2. Create the python binding
  3. Write the C++ .hh and .cc

Let's examine something already in gem5 first.

The Local Branch Predictor

Our case study is the local branch predictor, implemented in the 2bit_local.{cc hh} files. This is the simple 2-bit saturating branch predictor that you studied in class, and it demonstrates all the integral parts to the creation of an object in gem5.

My Apologies

I'm going to introduce this to you in a bit of a messed up order:

  1. Python binding
  2. Implementation
  3. Registration

I'm doing this not to confuse you, but rather because they all kind of flow together like this. Generally your implementation should follow the original order because it's easier to debug once you know the way everything works. I guess what I'm trying to say is "just trust me bro".

trust me

Python Implementation

First let's open $GEM_SRC/cpu/pred/BranchPredictor.py and find class LocalBP(...):

BranchPredictor.py
class LocalBP(BranchPredictor):
type = "LocalBP"
cxx_class = "gem5::branch_prediction::LocalBP"
cxx_header = "cpu/pred/2bit_local.hh"

localPredictorSize = Param.Unsigned(2048, "Size of local predictor")
localCtrBits = Param.Unsigned(2, "Bits per counter")

Upon examination, we can divide this into three essential components:

  1. type: this is how we need to reference this object in the python scripts
  2. cxx_{class header}: this gives binding information to link the behavior of the object (written in C++) to the use of the object (written in the user's python scripts)
  3. Param.*: These are parameters that can be modified through the user's python scripts. They reflect constructor variables in the gem5 objects.

Congrats, you now know how the python binding for the object works. This file contains all of the important information for binding python with the C++ objects, and serves as an outline for the C++ implementation.

C++ Implementation

The implemetation of the branch predictor is split over 2bit_local.{hh cc}, but since you can read code, I will only go through the .hh file here. The actual implementation is something you will have to work through for assignment 2 anyways 😘.

First, let's take a look at the header. I will abridge imports and comments, just for the sake of verbosity (and because I hope to explain it well enough that when you read the source code you can just follow along):

2bit_local.hh
namespace gem5 {
namespace branch_prediction {

class LocalBP: public BPredUnit {

public:
bool lookup(...);
void updateHistories(...);
void update(...);
void squash(...);

private:
...
};

}} // end of namespaces gem5 and branch_prediction
note

As of gem5 version 21, the developers improved the namespace seperation of the gem5 system. This included the adoption of clean, modular namespaces in the entire codebase. In this case, we can see that in the use of namespace gem5 and namespace branch_prediction.

The key part here is the inheritance from the BPredUnit, which provides all the functionality you need to interface with branch prediction. I will go through how to create a basic object from scratch in the next section, but in general this is the form you should follow for 90% of your contributions, as it is rare that you need to implement something from scratch.

You might find it useful to peruse the .cc file for your own information, but I won't cover that here since the inheritance pretty much templates your whole implementation in this case.

Registration

Now you get to experience the beauty of SCons.

Informational/Biased

SCons is a python based build system that some prefer for building complex C++ projects over CMAKE. If you want more information about it, you can visit their website.

The argument is that you can specifiy everything in a real programming language. Personally, I think that is a drawback because if you have any sense you shouldn't need a full programming language to specify how to build your project. Also python is sloooow.

HOWEVER in the case of gem5, it makes sense. With as many build targets as they have... mad respect... mad respect....

But you do you I guess.

To register the implementation with the SCons build system, you need to modify the SConscript file in the directory:

SimObject('BranchPredictor.py',
sim_objects=[
'BranchPredictor',
'IndirectPredictor', 'SimpleIndirectPredictor',
'BranchTargetBuffer', 'SimpleBTB',
'ReturnAddrStack',
'LocalBP', 'TournamentBP', 'BiModeBP', 'TAGEBase', 'TAGE', 'LoopPredictor',
'TAGE_SC_L_TAGE', 'TAGE_SC_L_TAGE_64KB', 'TAGE_SC_L_TAGE_8KB',
'LTAGE', 'TAGE_SC_L_LoopPredictor', 'StatisticalCorrector', 'TAGE_SC_L',
'TAGE_SC_L_64KB_StatisticalCorrector',
'TAGE_SC_L_8KB_StatisticalCorrector',
'TAGE_SC_L_64KB', 'TAGE_SC_L_8KB', 'MultiperspectivePerceptron',
'MultiperspectivePerceptron8KB', 'MultiperspectivePerceptron64KB',
'MPP_TAGE', 'MPP_LoopPredictor', 'MPP_StatisticalCorrector',
'MultiperspectivePerceptronTAGE', 'MPP_StatisticalCorrector_64KB',
'MultiperspectivePerceptronTAGE64KB', 'MPP_TAGE_8KB',
'MPP_LoopPredictor_8KB', 'MPP_StatisticalCorrector_8KB',
'MultiperspectivePerceptronTAGE8KB'],
enums=['BranchType', 'TargetProvider'])

Source('bpred_unit.cc')
Source('2bit_local.cc')
...

Note that in this case all you need to do is add the predictor to the list of SimObjects to provide from this module and specify the source directory.