Back

# Emulation Programming

Tue Aug 12 2025

About emulation programmming and emulators in general

Yo! I have been reading about emulators for quite while now. I decided to write this blog to share some stuff I have learnt and also these will be notes for me as well. I will continue updating this as my understanding grows.

What/ Why

How to emulate

Interpreted Emulation

C trick in emulators to access the same register data in multiple ways

typedef union
{
    UINT32 w;   /* Access it as a 32-bit value (maybe for full register set) */
    UINT16 w;   /* Access it as a 16-bit value */
    struct
    {
        UINT8 l, h;  /* Low and High byte parts */
        UINT16 pad;  /* Padding for little-endian alignment */
    } b;       /* Access as two bytes */
} i8080Reg;

Instructions, flag, memory and interrupts

Given is a basic instruction operation performed during emulation.

instruction (operands){
    get_operands;
    perform_calculations;
    store_result;
    update_time;
    return to the main loop / fetch next opcode;
}

Flags

Memory

Other Performance Concenrs

  1. Alignment Checks - Some CPUs forbid multi-byte reads/writes to unaligned addresses (e.g., reading a 32-bit word from address 0x0001). You must check and raise that exception
  2. Endianness conversion - If the emulated CPU uses a different byte order (big-endian vs. little-endian) than the host then every multi-byte read/write needs byte swapping

** So, interpreted emulation can be quite slow, but you can make them fast by writing them in assembly instead ;).


Making NES Emulator

CPU Core

#ifndef CPU6502_H
#define CPU6502_H
#include 

typedef union {
    uint16_t w;
    struct {
        #if **BYTE_ORDER** == **ORDER_LITTLE_ENDIAN**
            uint8_t l;
            uint8_t h;
        #else
            uint8_t h;
            uint8_t l;
        #endif
    } b;
} reg16_t;

typedef struct {
    uint8_t A;
    uint8_t X, Y;
    uint8_t P;
    uint8_t SP;
    reg16_t PC;
    uint64_t cycles;
} CPU6502;

enum{
    C_FLAG = 1 << 0,
    Z_FLAG = 1 << 1,
    I_FLAG = 1 << 2,
    D_FLAG = 1 << 3,
    B_FLAG = 1 << 4,
    U_FLAG = 1 << 5,
    V_FLAG = 1 << 6,
    N_FLAG = 1 << 7
};

void cpu_reset(CPU6502 *cpu, uint8_t (*read)(uint16_t));
void cpu_step(CPU6502 *cpu, uint8_t (*read)(uint16_t), void(\*write)(uint16_t, uint8_t));

#endif


References