v6502
The MOS 6502 Virtual Machine and Toolchain Infrastructure
Virtual Machine

Interactive VM

The included v6502 executable that is built using the v6502 API provides an interactive debugger to a v6502 instance that allows arbitrary manipulation of the machine and loading of data into memory. The interpreter will accept any valid 6502 assembly as instructions to execute in-place without stepping the CPU. The prompt always displays the current program counter address in hex, when halted. When running the CPU can be interrupted with a SIGINT or ^C. Binary images can be specified as arguments prior to runtime and automatically run on start.

The non-assembly commands are as follows:

cpu                 Displays the current state of the CPU.
disassemble <addr>  Disassemble 10 instructions starting at a given address, or the program counter if no address is specified.
help                Displays this help.
load <file>         Load binary image into memory at 0x0600.
peek <addr>         Dumps the memory at and around a given address.
quit                Exits v6502.
run                 Contunuously steps the cpu until a 'brk' instruction is encountered.
reset               Resets the CPU.
mreset              Zeroes all memory.
step                Forcibly steps the CPU once.
verbose             Toggle verbose mode; prints each instruction as they are executed when running.

The command interpreter supports shortening of these commands as far as possible without being ambiguous. Ambiguous commands have an arbitrary priority based on usefulness.

Example usage (debugging a binary):

Creating 1 virtual CPU…
Allocating 64k of virtual memory…
Resetting CPU…
Loading binary image "overflow.o" into memory…
Loaded 137 bytes.
Running…
Encountered 'brk' at 0x03.
(0x0004) disass $0600
0x0600: d8       - cld 
0x0601: a9 01    - lda #$01
0x0603: 8d 00 00 - sta $0000
0x0606: a9 80    - lda #$80
0x0608: 8d 00 00 - sta $0000
0x060b: 8d 00 00 - sta $0000
0x060e: a9 00    - lda #$00
0x0610: 8d 00 00 - sta $0000
0x0613: 8d 00 00 - sta $0000
0x0616: a0 01    - ldy #$01
(0x0004) v
Verbose mode enabled.
(0x0004) reset
(0x0600) r
0x0600: d8       - cld 
0x0601: a9 01    - lda #$01
0x0603: 8d 00 00 - sta $0000
0x0606: a9 80    - lda #$80
    … 20 lines ommitted …
0x061d: f0 1f    - beq $1f
0x063e: 60       - rts 
0x0003: 00       - brk 
Encountered 'brk' at 0x03.
(0x0004) cpu
Status Register: --XB-IZ-
CPU 0x100103a90: pc = 0x0004, ac = 0x00, x = 0x01, y = 0x01, sr = 0x36, sp = 0x01
MEM 0x100103ab0: memsize = 65535 (0xffff)
(0x0004) 

API

The simplest fault tolerant implementation of a v6502 instance, using the v6502 API, is as follows:

#include <v6502/cpu.h>
#include <v6502/mem.h>
void fault(void *ctx, const char *e) {
(*(int *)ctx)++;
}
int main(int argc, const char * argv[])
{
int faulted = 0;
cpu->memory = v6502_createMemory(2048);
cpu->fault_callback = fault;
cpu->fault_context = &faulted;
while (!faulted) {
v6502_step(cpu);
}
}

It is worth noting that this code will run the cpu at the fastest possible speed, with no regulation of timing. This is important for applications that expect a working CPU clock.