# Linux Kernel Module Cheat

#### 24.22.5. gem5 instruction definitions

This is one of the parts of gem5 that rely on semi-useless code generation inside the `.isa` sublanguage.

Which is mostly Python, with some magic letters thrown in for good measure.

The class definitions get all dumped into one humongous C++ include file:

    build/ARM/arch/arm/generated/exec-ns.cc.inc

That file defines the key methods of each instruction, e.g. the ARM immediate ADD instruction has its `execute` method defined there:

        Fault AddImm::execute(
            ExecContext *xc, Trace::InstRecord *traceData) const

or for example the key methods of an ARM 64-bit (X) STR with an immediate offset (`STR <Wt>, [<Xn|SP>], #<simm>`):

        Fault STRX64_IMM::execute(ExecContext *xc,
                                      Trace::InstRecord *traceData) const

        Fault STRX64_IMM::initiateAcc(ExecContext *xc,
                                          Trace::InstRecord *traceData) const

        Fault STRX64_IMM::completeAcc(PacketPtr pkt, ExecContext *xc,
                                          Trace::InstRecord *traceData) const
        {
            return NoFault;
        }

We also notice that the key argument passed to those instructions is of type `ExecContext`, which is discussed further at: Section 24.22.6.3, “gem5 `ExecContext`”.

The file is an include so that compilation can be split up into chunks by the autogenerated includers

    build/ARM/arch/arm/generated/generic_cpu_1.cc
    build/ARM/arch/arm/generated/generic_cpu_2.cc
    ...

via the `__SPLIT` macro as in:

    #include "exec-g.cc.inc"
    #include "cpu/exec_context.hh"
    #include "decoder.hh"
    namespace ArmISAInst {
    #define __SPLIT 1
    #include "exec-ns.cc.inc"
    }

This is likely done to not overload the C++ compiler? But sure enough overloads IDEs and GDB which takes forever to load the source of any frames going through it.

We should split that file into one per class for the love of God.

The autogenerated instruction class declarations can be found at:

    build/ARM/arch/arm/generated/decoder-ns.hh.inc

and the autogenerated bulk of the decoder:

    build/ARM/arch/arm/generated/decoder-ns.cc.inc

which also happens to contain the constructor definitions of the instruction classes, e.g. for the ADD immediate because why not:

        AddImm::AddImm(ExtMachInst machInst,
                                              IntRegIndex _dest,
                                              IntRegIndex _op1,
                                              uint32_t _imm,
                                              bool _rotC)

The above files get tied in the autogenerated:

    build/ARM/arch/arm/generated/decoder.hh

which contains:

    #include "decoder-g.hh.inc"
    namespace ArmISAInst {
    #include "decoder-ns.hh.inc"
    }

Different instructions inherit form different classes, e.g. the ARM immediate ADD instruction is a `DataImmOp`:

    class AddImm : public DataImmOp
    {
        public:
            // Constructor
            AddImm(ExtMachInst machInst, IntRegIndex _dest,
                    IntRegIndex _op1, uint32_t _imm, bool _rotC=true);
            Fault execute(ExecContext *, Trace::InstRecord *) const override;
    };

and STRX64_IMM is an `ArmISA::MemoryImm64`:

        class STRX64_IMM : public ArmISA::MemoryImm64
        {
          public:

            /// Constructor.
            STRX64_IMM(ExtMachInst machInst,
                    IntRegIndex _dest, IntRegIndex _base, int64_t _imm);

            Fault execute(ExecContext *, Trace::InstRecord *) const override;
            Fault initiateAcc(ExecContext *, Trace::InstRecord *) const override;
            Fault completeAcc(PacketPtr, ExecContext *,
                              Trace::InstRecord *) const override;

            void
            annotateFault(ArmFault *fault) override
            {
                        fault->annotate(ArmFault::SAS, 3);
                        fault->annotate(ArmFault::SSE, false);
                        fault->annotate(ArmFault::SRT, dest);
                        fault->annotate(ArmFault::SF, true);
                        fault->annotate(ArmFault::AR, false);
            }
        };

but different memory instructions can have different base classes too e.g. STXR:

    class STXRX64 : public ArmISA::MemoryEx64

A summarized class hierarchy for the above is:

- `StaticInst`

  - `ArmISA::ArmStaticInst`

    - `ArmISA::PredOp`

      - `ArmISA::DataImmOp`

        - `ArmISA::AddImm`

      - `ArmISA::MightBeMicro64`

        - ArmISA::Memory64

          - `ArmISA::MemoryImm64`

            - `ArmISA::MemoryEx64`

              - `ArmISA::STXRX64`

Tested in gem5 b1623cb2087873f64197e503ab8894b5e4d4c7b4.

- gem5 <code>execute</code> vs <code>initiateAcc</code> vs <code>completeAcc</code>

- gem5 microops