# Linux Kernel Module Cheat

###### 24.22.4.2.2. TimingSimpleCPU analysis #1

Backtrace:

    EventManager::schedule
    DRAMCtrl::Rank::startup
    DRAMCtrl::startup

Snippets:

    void
    DRAMCtrl::startup()
    {
        // remember the memory system mode of operation
        isTimingMode = system()->isTimingMode();

        if (isTimingMode) {
            // timestamp offset should be in clock cycles for DRAMPower
            timeStampOffset = divCeil(curTick(), tCK);

            // update the start tick for the precharge accounting to the
            // current tick
            for (auto r : ranks) {
                r->startup(curTick() + tREFI - tRP);
            }

            // shift the bus busy time sufficiently far ahead that we never
            // have to worry about negative values when computing the time for
            // the next request, this will add an insignificant bubble at the
            // start of simulation
            nextBurstAt = curTick() + tRP + tRCD;
        }
    }

which then calls:

    void
    DRAMCtrl::Rank::startup(Tick ref_tick)
    {
        assert(ref_tick > curTick());

        pwrStateTick = curTick();

        // kick off the refresh, and give ourselves enough time to
        // precharge
        schedule(refreshEvent, ref_tick);
    }

`DRAMCtrl::startup` is itself a `SimObject` method exposed to Python and called from `simulate` in `src/python/m5/simulate.py`:

    def simulate(*args, **kwargs):
        global need_startup

        if need_startup:
            root = objects.Root.getInstance()
            for obj in root.descendants(): obj.startup()

where `simulate` happens after `m5.instantiate`, and both are called directly from the toplevel scripts, e.g. for se.py in `configs/common/Simulation.py`:

    def run(options, root, testsys, cpu_class):
        ...
                exit_event = m5.simulate()

By looking up some variable definitions in the source, we now we see some memory parameters clearly:

- ranks: `std::vector<DRAMCtrl::Rank*>` with 2 elements. TODO why do we have 2? What does it represent? Likely linked to `config.ini` at `system.mem_ctrls.ranks_per_channel=2`: https://en.wikipedia.org/wiki/Memory_rank

- `tCK=1250`, `tREFI=7800000`, `tRP=13750`, `tRCD=13750`: all defined in a single code location with a comment:

           /**
           * Basic memory timing parameters initialized based on parameter
           * values.
           */

  Their values can be seen under `config.ini` and they are documented in `src/mem/DRAMCtrl.py` e.g.:

          # the base clock period of the DRAM
          tCK = Param.Latency("Clock period")

          # minimum time between a precharge and subsequent activate
          tRP = Param.Latency("Row precharge time")

          # the amount of time in nanoseconds from issuing an activate command
          # to the data being available in the row buffer for a read/write
          tRCD = Param.Latency("RAS to CAS delay")

          # refresh command interval, how often a "ref" command needs
          # to be sent. It is 7.8 us for a 64ms refresh requirement
          tREFI = Param.Latency("Refresh command interval")

So we realize that we are going into deep DRAM modelling, more detail that a mere mortal should ever need to know.

`curTick() + tREFI - tRP = 0 + 7800000 - 13750 = 7786250` which is when that `refreshEvent` was scheduled. Our simulation ends way before that point however, so we will never know what it did thank God.