The ChampSim Module System

ChampSim provides a runtime module system that allows you to swap implementations of key simulator components without recompilation. Each component type has an interface (a C++ abstract base class with pure virtual methods) and one or more implementations (concrete classes that override every method). ChampSim ships default implementations for all interfaces; you can replace any of them with your own.

Modules are implemented as C++ classes that inherit from an interface base class in the champsim::modules namespace. Every module:

  1. Inherits from one of the interface base classes listed below.

  2. Implements every pure virtual method declared by that interface (use empty stubs override {} for methods where no behavior is needed).

  3. Accepts a champsim::modules::ModuleBuilder in its constructor to receive configuration parameters and access its parent module.

  4. Registers itself with a static registration line so the simulator can instantiate it by name at runtime.

Interfaces and Implementations

ChampSim distinguishes between interfaces and implementations:

  • An interface is an abstract base class that defines the contract a module must fulfill. Interfaces live in champsim::modules and have names like prefetcher, replacement, branch_predictor, btb, cache_module, core_module, etc.

  • An implementation is a concrete class that inherits from an interface and provides the actual behavior. ChampSim ships default implementations (e.g. DEFAULT_CACHE, DEFAULT_CORE, lru, hashed_perceptron, ip_stride, etc.).

When writing a new module, you implement an existing interface. The four user-facing module interfaces are:

  • champsim::modules::branch_predictor — attached to a core

  • champsim::modules::btb — attached to a core

  • champsim::modules::prefetcher — attached to a cache

  • champsim::modules::replacement — attached to a cache

Higher-level interfaces (cache_module, core_module, memory_controller_module, etc.) define the contracts that caches, cores, and DRAM controllers fulfill. The default implementations DEFAULT_CACHE (CACHE class) and DEFAULT_CORE (O3_CPU class) implement these interfaces. See Cache Model and Core Model for details.

Module Construction and ModuleBuilder

All modules receive a champsim::modules::ModuleBuilder in their constructor. The ModuleBuilder provides:

  • Configuration parameters from the JSON config file via get_parameter<T>().

  • Access to the parent module via get_parent<T>(). For example, a prefetcher can obtain a pointer to its parent cache.

  • The module’s name and model via get_name() and get_model().

Example constructor:

struct my_pref : champsim::modules::prefetcher {
    champsim::modules::cache_module* cache_ = nullptr;
    int degree = 3;

    my_pref(champsim::modules::ModuleBuilder builder)
        : cache_(builder.get_parent<champsim::modules::cache_module>()),
          degree(builder.get_parameter<int>("degree", true, 3))
    {}
};
struct ModuleBuilder

Provides configuration parameters and parent access to modules during construction.

Every module constructor receives a ModuleBuilder. Use it to:

Public Functions

template<typename T>
inline T get_parameter(std::string name, bool optional = false, T default_value = T{}) const

Retrieve a configuration parameter by name.

Parameters are set in the JSON configuration file. For example, if the config contains {"model": "my_pref", "degree": 4}, then get_parameter<int>("degree") returns 4.

Template Parameters:

T – The expected type of the parameter.

Parameters:
  • name – The parameter name as it appears in the JSON config.

  • optional – If true, returns default_value when the parameter is absent. If false (the default), the simulator exits with an error.

  • default_value – The value to return when the parameter is absent and optional is true.

Returns:

The parameter value, or default_value if absent and optional.

inline std::string get_model() const

Return the model name of this module (e.g. "ip_stride").

inline std::string get_name() const

Return the instance name of this module (e.g. "cpu0_L2C.ip_stride").

template<typename T>
inline T *get_parent() const

Return a typed pointer to this module’s parent.

For prefetchers and replacement policies the parent is a cache_module. For branch predictors and BTBs the parent is a core_module.

Template Parameters:

T – The parent module type (e.g. cache_module or core_module).

Returns:

A pointer to the parent module.

Module Registration

After defining your module class, register it with a static registration line in the .cc file:

#include "my_pref.h"
#include "cache.h"

champsim::modules::prefetcher::register_module<my_pref> my_pref_register("my_pref");

The string "my_pref" is the model name — this is the value you use in the JSON configuration file to select your module:

{ "L2C": { "prefetcher": "my_pref" } }

Or in the explicit config format:

{ "name": "L2C_prefetcher", "module": "prefetcher", "model": "my_pref", "degree": 4 }

By convention, the model name matches the directory name under prefetcher/, replacement/, branch/, or btb/.

Branch Predictors

A branch predictor module inherits from champsim::modules::branch_predictor and must implement three functions.

struct branch_predictor : public champsim::modules::module_base<branch_predictor, core_module>

Interface for branch predictor modules.

Branch predictors are attached to a core (core_module). Implement the three virtual methods below and register with register_module to create a custom branch predictor.

Public Functions

virtual void initialize_branch_predictor() = 0

Called when the core is initialized. Use this to set up dynamic data structures.

virtual void last_branch_result(champsim::address ip, champsim::address target, bool taken, uint8_t branch_type) = 0

Called when a branch is resolved. All parameters are guaranteed correct.

Parameters:
  • ip – The instruction pointer of the branch.

  • target – The correct target of the branch.

  • taken – True if the branch was taken.

  • branch_type – One of BRANCH_DIRECT_JUMP, BRANCH_INDIRECT, BRANCH_CONDITIONAL, BRANCH_DIRECT_CALL, BRANCH_INDIRECT_CALL, BRANCH_RETURN, or BRANCH_OTHER.

virtual bool predict_branch(champsim::address ip, champsim::address predicted_target, bool always_taken, uint8_t branch_type) = 0

Called when a branch direction prediction is needed.

Parameters:
  • ip – The instruction pointer of the branch.

  • predicted_target – The predicted target from the BTB (may be incorrect).

  • always_taken – True if the BTB determines the branch is always taken.

  • branch_type – One of BRANCH_DIRECT_JUMP, BRANCH_INDIRECT, BRANCH_CONDITIONAL, BRANCH_DIRECT_CALL, BRANCH_INDIRECT_CALL, BRANCH_RETURN, or BRANCH_OTHER.

Returns:

True if the branch is predicted taken, false otherwise.

Branch Target Buffers

A BTB module inherits from champsim::modules::btb and must implement three functions.

struct btb : public champsim::modules::module_base<btb, core_module>

Interface for branch target buffer (BTB) modules.

BTBs are attached to a core (core_module). Implement the three virtual methods below and register with register_module to create a custom BTB.

Public Functions

virtual void initialize_btb() = 0

Called when the core is initialized. Use this to set up dynamic data structures.

virtual void update_btb(champsim::address ip, champsim::address predicted_target, bool taken, uint8_t branch_type) = 0

Called when a branch is resolved.

Parameters:
  • ip – The instruction pointer of the branch.

  • predicted_target – The correct target of the branch.

  • taken – True if the branch was taken.

  • branch_type – One of BRANCH_DIRECT_JUMP, BRANCH_INDIRECT, BRANCH_CONDITIONAL, BRANCH_DIRECT_CALL, BRANCH_INDIRECT_CALL, BRANCH_RETURN, or BRANCH_OTHER.

virtual std::pair<champsim::address, bool> btb_prediction(champsim::address ip, uint8_t branch_type) = 0

Called when a branch target prediction is needed.

Parameters:
  • ip – The instruction pointer of the branch.

  • branch_type – One of the branch type constants.

Returns:

A pair of (predicted target address, always-taken flag). Return {champsim::address{}, false} if prediction fails.

Memory Prefetchers

A prefetcher module inherits from champsim::modules::prefetcher and must implement six functions. The prefetch_line() helper is provided by the base class for issuing prefetch requests into the parent cache.

struct prefetcher : public champsim::modules::module_base<prefetcher, cache_module>

Interface for memory prefetcher modules.

Prefetchers are attached to a cache (cache_module). Implement the six virtual methods below and register with register_module to create a custom prefetcher. Use prefetch_line() to issue prefetch requests.

Public Functions

virtual void prefetcher_initialize() = 0

Called when the cache is initialized. Use this to set up dynamic data structures.

virtual uint32_t prefetcher_cache_operate(champsim::address addr, champsim::address ip, bool cache_hit, bool useful_prefetch, access_type type, uint32_t metadata_in) = 0

Called when a tag check is performed in the cache.

Parameters:
  • addr – The address of the packet. Includes offset bits for L1 caches; zero offset otherwise. If virtual_prefetch is true, this is a virtual address.

  • ip – The instruction pointer that initiated the demand. Zero for prefetches from other levels.

  • cache_hit – True if this tag check is a hit.

  • useful_prefetch – True if this tag check hit a prior prefetch.

  • type – The access type (LOAD, RFO, PREFETCH, WRITE, or TRANSLATION).

  • metadata_in – Metadata carried by the packet.

Returns:

Metadata to store alongside the block.

virtual uint32_t prefetcher_cache_fill(champsim::address addr, long set, long way, bool prefetch, champsim::address evicted_addr, uint32_t metadata_in) = 0

Called when a miss is filled in the cache.

Parameters:
  • addr – The address of the filled block (same addressing rules as prefetcher_cache_operate).

  • set – The cache set that the fill occurred in.

  • way – The cache way that the fill occurred in.

  • prefetch – True if the filled block was a prefetch.

  • evicted_addr – The address of the evicted block (default-constructed if bypass).

  • metadata_in – Metadata carried by the packet.

Returns:

Metadata to store alongside the block.

virtual void prefetcher_cycle_operate() = 0

Called each cycle after all other cache operations have completed.

virtual void prefetcher_final_stats() = 0

Called at the end of the simulation. Can be used to print statistics.

virtual void prefetcher_branch_operate(champsim::address ip, uint8_t branch_type, champsim::address branch_target) = 0

Called on branch operations. Useful for instruction prefetchers.

Parameters:
  • ip – The instruction pointer of the branch.

  • branch_type – One of BRANCH_DIRECT_JUMP, BRANCH_INDIRECT, BRANCH_CONDITIONAL, BRANCH_DIRECT_CALL, BRANCH_INDIRECT_CALL, BRANCH_RETURN, or BRANCH_OTHER.

  • branch_target – The target address of the branch.

bool prefetch_line(champsim::address pf_addr, bool fill_this_level, uint32_t prefetch_metadata) const

Issue a prefetch request into the parent cache.

This delegates to the parent cache’s prefetch mechanism. You do not need to store your own parent pointer to use this method.

Parameters:
  • pf_addr – The address to prefetch.

  • fill_this_level – If true, fill this cache level; otherwise fill the next level down.

  • prefetch_metadata – Metadata to associate with the prefetch.

Returns:

True if the prefetch was successfully enqueued.

bool prefetch_line(uint64_t pf_addr, bool fill_this_level, uint32_t prefetch_metadata) const

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

Replacement Policies

A replacement policy module inherits from champsim::modules::replacement and must implement five functions.

struct replacement : public champsim::modules::module_base<replacement, cache_module>

Interface for cache replacement policy modules.

Replacement policies are attached to a cache (cache_module). Implement the five virtual methods below and register with register_module to create a custom replacement policy.

Public Functions

virtual void initialize_replacement() = 0

Called when the cache is initialized. Use this to set up dynamic data structures.

virtual long find_victim(uint32_t triggering_cpu, uint64_t instr_id, long set, const champsim::cache_block *current_set, champsim::address ip, champsim::address full_addr, access_type type) = 0

Called when a cache miss requires eviction.

Parameters:
  • triggering_cpu – The core index that initiated this access.

  • instr_id – Instruction count for examining program order of requests.

  • set – The cache set being accessed.

  • current_set – A pointer to the beginning of the set being accessed.

  • ip – The instruction that initiated the demand. Zero for prefetches from other levels.

  • full_addr – The address of the packet.

  • type – The access type (LOAD, RFO, PREFETCH, WRITE, or TRANSLATION).

Returns:

The way index to evict, or the total number of ways to bypass.

virtual void update_replacement_state(uint32_t triggering_cpu, long set, long way, champsim::address full_addr, champsim::address ip, champsim::address victim_addr, access_type type, bool hit) = 0

Called when a tag check completes (on both hits and misses).

Parameters:
  • triggering_cpu – The core index that initiated this access.

  • set – The cache set.

  • way – The cache way.

  • full_addr – The address of the packet.

  • ip – The instruction that initiated the demand.

  • victim_addr – The address of the evicted block (zero on hits).

  • type – The access type.

  • hit – True if the packet hit the cache.

virtual void replacement_cache_fill(uint32_t triggering_cpu, long set, long way, champsim::address full_addr, champsim::address ip, champsim::address victim_addr, access_type type) = 0

Called when a block is filled in the cache.

This is called with the same timing as find_victim(), and is additionally called when filling an invalid way.

Parameters:
  • triggering_cpu – The core index that initiated this fill.

  • set – The cache set.

  • way – The cache way.

  • full_addr – The address of the filled block.

  • ip – The instruction that initiated the demand.

  • victim_addr – The address of the evicted block (zero on hits).

  • type – The access type.

virtual void replacement_final_stats() = 0

Called at the end of the simulation. Can be used to print statistics.

Cache Module Interface

The cache_module interface defines the contract that caches fulfill. Prefetchers and replacement policies can query their parent cache through this interface, for example to read queue occupancy or cache geometry.

struct cache_module : public champsim::modules::module_base<cache_module, environment_module>, public champsim::operable

Interface for cache modules.

The default implementation is CACHE. Prefetchers and replacement policies are attached to a cache_module. Module authors can query cache geometry and queue occupancy through this interface.

Subclassed by CACHE

Public Types

using stats_type = cache_stats

The stats type returned by get_sim_stats() and get_roi_stats().

Public Functions

virtual stats_type get_sim_stats() const = 0

Return simulation-wide statistics for this cache.

virtual stats_type get_roi_stats() const = 0

Return region-of-interest statistics for this cache.

virtual bool is_virtual_prefetch() const = 0

Return true if this cache uses virtual addresses for prefetching.

virtual bool prefetch_line(champsim::address pf_addr, bool fill_this_level, uint32_t prefetch_metadata) = 0

Issue a prefetch into this cache.

Parameters:
  • pf_addr – The address to prefetch.

  • fill_this_level – If true, fill this cache level; otherwise fill the next level.

  • prefetch_metadata – Metadata to associate with the prefetch.

Returns:

True if the prefetch was successfully enqueued.

virtual long invalidate_entry(champsim::address inval_addr) = 0

Invalidate the cache line at the given address. Returns the way index, or -1.

virtual std::size_t get_mshr_occupancy() const = 0

Return the current number of occupied MSHR entries.

virtual std::size_t get_mshr_size() const = 0

Return the total MSHR capacity.

virtual double get_mshr_occupancy_ratio() const = 0

Return the MSHR occupancy as a ratio in [0, 1].

virtual std::vector<std::size_t> get_rq_occupancy() const = 0

Return per-channel read queue occupancy.

virtual std::vector<std::size_t> get_rq_size() const = 0

Return per-channel read queue capacity.

virtual std::vector<double> get_rq_occupancy_ratio() const = 0

Return per-channel read queue occupancy as a ratio in [0, 1].

virtual std::vector<std::size_t> get_wq_occupancy() const = 0

Return per-channel write queue occupancy.

virtual std::vector<std::size_t> get_wq_size() const = 0

Return per-channel write queue capacity.

virtual std::vector<double> get_wq_occupancy_ratio() const = 0

Return per-channel write queue occupancy as a ratio in [0, 1].

virtual std::vector<std::size_t> get_pq_occupancy() const = 0

Return per-channel prefetch queue occupancy.

virtual std::vector<std::size_t> get_pq_size() const = 0

Return per-channel prefetch queue capacity.

virtual std::vector<double> get_pq_occupancy_ratio() const = 0

Return per-channel prefetch queue occupancy as a ratio in [0, 1].

virtual std::size_t num_sets() const = 0

Return the number of sets in this cache.

virtual std::size_t num_ways() const = 0

Return the number of ways in this cache.

virtual champsim::data::bits get_offset_bits() const = 0

Return the number of offset bits (log2 of block size).

Core Module Interface

The core_module interface defines the contract that CPU cores fulfill. Branch predictors and BTBs are attached to a core_module.

struct core_module : public champsim::modules::module_base<core_module, environment_module>, public champsim::operable

Interface for CPU core modules.

The default implementation is O3_CPU. Branch predictors and BTBs are attached to a core_module.

Subclassed by O3_CPU

Public Types

using stats_type = cpu_stats

The stats type returned by get_sim_stats() and get_roi_stats().

Public Functions

virtual uint64_t sim_instr() const = 0

Return the number of instructions simulated so far.

virtual uint8_t get_cpu_num() const = 0

Return this core’s CPU index.

virtual uint64_t sim_cycle() const = 0

Return the number of cycles simulated so far.

virtual stats_type get_sim_stats() const = 0

Return simulation-wide statistics for this core.

virtual stats_type get_roi_stats() const = 0

Return region-of-interest statistics for this core.

Memory Controller Interface

The memory_controller_module interface defines the contract that DRAM controllers fulfill. Stats can be retrieved per channel.

struct memory_controller_module : public champsim::modules::module_base<memory_controller_module, environment_module>, public champsim::operable

Interface for DRAM memory controller modules.

The default implementation is MEMORY_CONTROLLER. Stats can be retrieved per channel.

Subclassed by MEMORY_CONTROLLER

Public Types

using stats_type = dram_stats

The stats type returned by get_sim_stats() and get_roi_stats().

Public Functions

virtual std::size_t get_num_channels() const = 0

Return the number of DRAM channels.

virtual stats_type get_sim_stats(std::size_t channel_no) const = 0

Return simulation-wide statistics for the given channel.

virtual stats_type get_roi_stats(std::size_t channel_no) const = 0

Return region-of-interest statistics for the given channel.

virtual champsim::data::bytes size() const = 0

Return the total DRAM size.