LEVENT KAYA'S WEBSITE

CONTACT    RSS     DONATE


Oct 17, 2024
Graphical Integrated Debugging and Emulation Suite for 6502 CPU in C

comp

Hello everyone, in this blog post I will be explaining how and why I wrote the c6502, an integrated debugging and emulation suite that I developed for the MOS 6502.

A little bit of tech history

The MOS 6502 is one of the most influential microprocessors in computing history. Introduced in 1975 by MOS Technology, the 6502 was designed to be a low-cost, high-performance alternative to the more expensive processors of the time, such as Intel’s 8080 and Motorola’s 6800. What made the 6502 revolutionary was its affordability, which opened the door for hobbyists, smaller companies, and educational institutions to embrace computing at a time when prices were otherwise prohibitive.

The 6502 found its way into iconic devices like the Apple I and Apple II, the Commodore PET, and the Atari 2600, fueling the growth of personal computing and gaming in the late 1970s and early 1980s. Its simple yet powerful instruction set made it an excellent learning tool for budding engineers and programmers. Despite its simplicity, the 6502's efficiency and low transistor count allowed it to run at competitive speeds, solidifying its place in computing history. The design of the 6502 influenced later processors and remains a classic example of 8-bit microprocessor architecture.

Why?

When I started tinkering with 6502 assembly, I quickly realized there wasn’t a single tool that combined all the features I needed. Sure, there were great emulators, solid debuggers, and even some decompilers, but they were all separate. Switching between different programs disrupted the workflow, and I found myself wishing for an all-in-one tool that could handle emulation, debugging, and decompilation seamlessly. So, I created one :)

The goal

My biggest goal while writing c6502 was to make this software actually run the assembly and binary files written for mos6502. And that's what happened. For this, I used the ca65 assembler and ld65 linker provided by cc65 and created my binary files. Then I was able to use these binary files with c6502.

A real 6502 code and binary that runs assembled on c6502:

bin

Another goal of mine was to be able to monitor the changes in memory and registers in real time. I made this possible with the c6502.

Features overview

The emulation process

In c6502, the emulation process is designed to closely mimic the behavior of the MOS 6502 processor, step by step. Let’s take a deeper dive.

1. Resetting the CPU

In c_reset() the registers (A, X, Y, PC, SP) and flags are initialized. Acc, X, Y → 0; PC → 0x0000; flags cleared so the CPU starts in a clean state.

2. Fetching the instruction

The opcode is fetched from memory at PC and logged:

uint8_t opcode = memory->mem[cpu->reg.pc];
printf("PC: 0x%04x, Opcode: 0x%02x\n", cpu->reg.pc, opcode);
3. Decoding the instruction

The fetched opcode is matched against the instruction table:

for (size_t i = 0; i < set_size; i++) {
    if (opcode == instruction_set[i].opcode) {
      instruction = &instruction_set[i];
      break;
    }
}
4. Addressing modes

Addressing mode determines how to obtain operands (immediate/absolute/zero page/etc.). Example absolute:

uint16_t address = ((mem->mem[cpu->reg.pc + 2] << 8) | mem->mem[cpu->reg.pc + 1]);
5. Executing instructions

Example LDA handler:

void lda_handler(c_cpu_t *cpu, m_memory_t *mem, uint16_t address)
{
  cpu->reg.acc = mem->mem[address];
  if (cpu->reg.acc == 0) {{ SET_FLAG(cpu->reg, FLAG_ZERO); }}
  else {{ CLEAR_FLAG(cpu->reg, FLAG_ZERO); }}
  if (cpu->reg.acc & 0x80) {{ SET_FLAG(cpu->reg, FLAG_NEGATIVE); }}
  else {{ CLEAR_FLAG(cpu->reg, FLAG_NEGATIVE); }}
}
6. Putting all together

Reset → fetch → decode → address → execute, looped—mirroring the original hardware while exposing a transparent, real-time debugging view.

The c6502 User Interface

ui

The GUI keeps everything in one place for emulation, debugging, and reverse engineering.

1. Virtual interface

Main display area for visual output from the emulated system.

2. Disassembler

Live disassembly that follows execution and highlights the current instruction.

3. Register status

Real-time PC, SP, A, X, Y and flags view for quick feedback.

4. Memory status

Inspect memory values and how instructions affect them in real time.

Overall Design Philosophy

All critical info at a glance without switching tools—ideal for learning, debugging, and analysis.

Conclusion

Developing c6502 merged my love for retrocomputing with low-level programming and tool building. The result is a comprehensive suite that integrates emulation, debugging, and decompilation into a single, user-friendly tool. If you’re interested in trying it, grab it on GitHub.


← Back to Articles