Skip to content

Pure-C# 6502 emulator

KullGames.RetroCore

A real, from-scratch MOS 6502 (NMOS) CPU core - pure C#, single-stepped through hand-assembled machine code.

6502 emulator pure C# no BCL deps beyond .NET

This page is a static render of the console app's real captured output. The CPU is not reimplemented for the web - it is reused directly from the library leaf OnlyCSharp/1.8/ComputerEngineering.Processors.M6502 (Nmos6502 : M6502Core), the full 256-entry NMOS opcode table running against an injected IMemoryBus8. The app supplies only a flat 64 KiB RAM bus; every register transition, flag update, and branch below comes straight out of the real emulator.

The program (hand-assembled at $0600)

$0600: A2 00   LDX #$00        ; X = 0
$0602: 86 10   STX $10         ; loop: mem[$10] = X
$0604: E8      INX             ; X++
$0605: E0 0A   CPX #$0A        ; compare X to 10
$0607: D0 F9   BNE $0602       ; if X != 10, branch back (offset -7 = 0xF9)
$0609: 00      BRK

The reset vector ($FFFC/$FFFD) points at $0600, so the CPU boots straight into it.

Real captured output

KullGames.RetroCore -- a real MOS 6502 (NMOS) core, OnlyCSharp/1.8 ComputerEngineering.Processors.M6502
Program: count X from 0 to 9, storing X into zero-page $0010 every pass, then BRK.

#1  PC=$0602  A=$00 X=$00 Y=$00 P=$26
#2  PC=$0604  A=$00 X=$00 Y=$00 P=$26
#3  PC=$0605  A=$00 X=$01 Y=$00 P=$24
#4  PC=$0607  A=$00 X=$01 Y=$00 P=$A4
#5  PC=$0602  A=$00 X=$01 Y=$00 P=$A4
#6  PC=$0604  A=$00 X=$01 Y=$00 P=$A4
#7  PC=$0605  A=$00 X=$02 Y=$00 P=$24
#8  PC=$0607  A=$00 X=$02 Y=$00 P=$A4
#9  PC=$0602  A=$00 X=$02 Y=$00 P=$A4
#10  PC=$0604  A=$00 X=$02 Y=$00 P=$A4
#11  PC=$0605  A=$00 X=$03 Y=$00 P=$24
#12  PC=$0607  A=$00 X=$03 Y=$00 P=$A4
#13  PC=$0602  A=$00 X=$03 Y=$00 P=$A4
#14  PC=$0604  A=$00 X=$03 Y=$00 P=$A4
#15  PC=$0605  A=$00 X=$04 Y=$00 P=$24
#16  PC=$0607  A=$00 X=$04 Y=$00 P=$A4
#17  PC=$0602  A=$00 X=$04 Y=$00 P=$A4
#18  PC=$0604  A=$00 X=$04 Y=$00 P=$A4
#19  PC=$0605  A=$00 X=$05 Y=$00 P=$24
#20  PC=$0607  A=$00 X=$05 Y=$00 P=$A4
#21  PC=$0602  A=$00 X=$05 Y=$00 P=$A4
#22  PC=$0604  A=$00 X=$05 Y=$00 P=$A4
#23  PC=$0605  A=$00 X=$06 Y=$00 P=$24
#24  PC=$0607  A=$00 X=$06 Y=$00 P=$A4
#25  PC=$0602  A=$00 X=$06 Y=$00 P=$A4
#26  PC=$0604  A=$00 X=$06 Y=$00 P=$A4
#27  PC=$0605  A=$00 X=$07 Y=$00 P=$24
#28  PC=$0607  A=$00 X=$07 Y=$00 P=$A4
#29  PC=$0602  A=$00 X=$07 Y=$00 P=$A4
#30  PC=$0604  A=$00 X=$07 Y=$00 P=$A4
#31  PC=$0605  A=$00 X=$08 Y=$00 P=$24
#32  PC=$0607  A=$00 X=$08 Y=$00 P=$A4
#33  PC=$0602  A=$00 X=$08 Y=$00 P=$A4
#34  PC=$0604  A=$00 X=$08 Y=$00 P=$A4
#35  PC=$0605  A=$00 X=$09 Y=$00 P=$24
#36  PC=$0607  A=$00 X=$09 Y=$00 P=$A4
#37  PC=$0602  A=$00 X=$09 Y=$00 P=$A4
#38  PC=$0604  A=$00 X=$09 Y=$00 P=$A4
#39  PC=$0605  A=$00 X=$0A Y=$00 P=$24
#40  PC=$0607  A=$00 X=$0A Y=$00 P=$27
#41  PC=$0609  A=$00 X=$0A Y=$00 P=$27
#42  PC=$0000  A=$00 X=$0A Y=$00 P=$27

Final value at $0010: 9 (0x09)
Summary: 42 instructions retired, final X register = 10 (0x0A)

The real result: 9, not 10

STX $10 runs before INX each pass, so the ten stores write 0,1,2,...,9 - the byte left at $0010 is 9 (0x09), while X counts one step further to 10 (0x0A) to satisfy the CPX #$0A exit test. Step #42 executes BRK, which (this demo wires no BRK/IRQ vector at $FFFE/$FFFF) faithfully jumps PC to $0000 - real 6502 semantics, not a harness bug.