1

I am trying to make a CHIP-8 emulator that generates most of the instructions at compile time.

So i have a constexpr array like this:

constexpr uint16_t hardCodedROM[] = {
    0x8001, 0x8002, 0x8003, 0xA0F0, 0xB0FE
};

And I have a specialization for each item of the array like this:

template<uint16_t instruction> struct Opcode 
{
    static inline void Task(uint16_t code)
    { 
        printf("Unknown Opcode \n");
    }
};

template<> struct Opcode<0x8000>
{

    static inline auto Task(uint16_t code)
    {
        static constexpr unsigned char submask = code & 0x000F; //error here, code can not use as a constant

        if constexpr (submask == 0x0001)
        {
            printf("Opcode 0x8xx1 \n");
        }

        if constexpr (submask == 0x0002)
        {
            printf("Opcode 0x8xx2 \n");
        }

        if constexpr (submask == 0x0003)
        {
            printf("Opcode 0x8xx2 \n");
        }

        if constexpr (submask == 0x0000)
        {
            printf("Opcode 0x8xx0 \n");
        }
    }
};

template<> struct Opcode<0xA000>
{
    static inline auto Task(uint16_t code)
    {
        printf("Opcode 0xAxxx \n");
    }
};

template<> struct Opcode<0xB000>
{
    static inline auto Task(uint16_t code)
    {
        printf("Opcode 0xBxxx \n");
    }
};

And i iterate over each of the elements and invoke specialization in this way:

[&] <std::size_t...p>(std::index_sequence<p...>)
{
    (Opcode<(hardCodedROM[p] & 0xF000)>::Task(hardCodedROM[p]), ...); //How should i pass the element, to be able to evaluate depending on each submask?
}
(std::make_index_sequence<5>{});

How should i pass the element (hardCodedROM[p]), to be able to evaluate depending on each submask within a certain specialization?

  • `code` is going to be passed at runtime, yes? Something read from a file? That means it can't be a compile-time value, so you can't do compile-time conditionals on it or any value that is computed using it. – Nicol Bolas Jul 28 '20 at 05:25
  • @NicolBolas In theory they would pass via _fold expression_ in the std::make_index_sequence iteration at compile time – Iván Ayala Jul 28 '20 at 05:44
  • The ROM (or file) is hardcoded, represented by ```hardcodedROM[ ]``` – Iván Ayala Jul 28 '20 at 05:50
  • 1
    `[&](std::index_sequence)` is C++20, not C++17. – Evg Jul 28 '20 at 07:29

1 Answers1

1

If code is always known at compile time, make it a template parameter:

template<std::uint16_t code>
static void Task() {
    constexpr unsigned char submask = code & 0x000F;
    // ...
}

and then don't forget the template disambiguator:

[&]<std::size_t...p>(std::index_sequence<p...>) {
    (Opcode<(hardCodedROM[p] & 0xF000)>::template Task<hardCodedROM[p]>(), ...);
}
(std::make_index_sequence<5>{});

You can also wrap code into a type similar to Opcode and pass it as a function parameter to avoid pretty ugly template keyword. For example:

template<std::uint16_t> struct Instruction {};

// ...
    template<std::uint16_t code>
    static void Task(Instruction<code>) { 
        constexpr unsigned char submask = code & 0x000F;
        // ...
    }
// ...

[&]<std::size_t...p>(std::index_sequence<p...>) {
    (Opcode<(hardCodedROM[p] & 0xF000)>::Task(Instruction<hardCodedROM[p]>{}), ...);
}
(std::make_index_sequence<5>{});
Evg
  • 25,259
  • 5
  • 41
  • 83