c++assemblystaticchip-8

A variable is reverting to a previous value after being assigned to with an assignment statement


I am writing a simple chip8 emulator.

I have a value called programCounter(PC).

The problem is that once I return from the Instruction1( which modifies PC), PC returns to the value it was before being modified by the method.

Example

Before Instruction1 assigns to PC, the value of PC is 203.

After Instruction1, the value of PC is (0x0NNN & 0xFFFE).

By programCounter++, it return to 203 than increments.

#include <cstdint>

constexpr auto PROGRAMSTART = 0x200;
constexpr auto GRAPHICSTART = 0xF00;
constexpr auto GRAPHICEND = 0xFFF;

//Memory
static uint8_t memory[4096]; // 0x000-0xFFF -> 0000-4095
static uint16_t stack[16];

//General Purpose Registers
static uint8_t registers[16]; //Register V0,V1,..V9,VA,VB,..,VF

//Special Purpose Register
static uint8_t specialRegisters[2];
static uint8_t stackPointer;
static uint16_t registerI;
static uint16_t programCounter = PROGRAMSTART;

//Graphic
const int WIDTH = 64;
const int HEIGHT = 32;
const int beginnningOfGraphicMemory = 0xF00;

For instruction 1NNN("https://en.wikipedia.org/wiki/CHIP-8#Opcode_table"), It is a simple unconditional jump.

void Instruction1(uint16_t NNN)
{
    programCounter = (NNN & 0xFFFE); //Keeps the PC counter aligned to memory
}

int main()
{
    SetUpInterpreterText(0);
    Test();
    for (;;)
    {
        printf("Program Counter: %04x \n", programCounter);
        uint16_t byte0 = (memory[programCounter++] << 8);
        uint16_t byte1 = (memory[programCounter]);
        uint16_t instruction = byte0 + byte1; //must load data in 16bit chunks
        Decoder(instruction);
        printf("Program Counter: %04x  Data: %04x \n", programCounter, instruction);
        programCounter++;
        
    }
    return 0;
}

void Decoder(uint16_t instruction)
{
    uint16_t data = instruction & 0x0FFF; //removing the top 4 bits to make it easier
    switch (instruction >> 12)
    {
    case 0:
        Instruction0(data);
        break;
    case 1:
        Instruction1(data);
        break;
    default:
        std::cout << "Instruction Not Foud" << std::endl;
        exit(EXIT_FAILURE);
        break;
    }
}

All Decoder does is remove the top 4 bits for the instructions for a 16-bit instruction. For example, 0x1234 is sent to the 1NNN instruction/Method and the 234 represents the NNN part of the instruction.

I disassembled the program and according to the assembly, the PC is being stored in memory and once I get to the `programCounter++;' it is restored from memory. However, for the Instruction1, it doesn't write to memory it rights to the register EAX.

What should I do to let the compiler know that I want it to update the memory location of PC when ever I assign a value to it rather than just updating the register?

P.S. I have tried writing inline assembly but I am not that skilled at x86 assembly. I can't seem to move register_EAX to the memory location of the value so I can forcibly update value since EAX has the proper value until PC is incremented.


Solution

  • You have two or more cpp files. Each forms a compilation unit. (A .h you include becomes part of each compilation unit separately; the notion of compilation unit applies after preprocessing is done.)

    Static global variables are not linked between compilation units, they're private to the unit they're defined in.
    static uint16_t programCounter is thus local to each cpp file.

    As a general rule:

    1. Stop using global variables, especially mutable ones. Pass shared state explicitly. Use a class or struct.
    2. Especially stop using mutable static variables in header files. That is insane.
    3. Check the address of data when things don't make sense.

    Be aware that static has a different meaning within classes and functions that it does at global scope. Regular globals already have static storage class (same as static variables), but with global cross-file visibility.