fs2port/port/include/cpu6502.h
2026-05-13 21:32:05 -05:00

94 lines
3.5 KiB
C

// Minimal 6502 / 65C02 interpreter, extracted from tools/fs2trace.c
// so chunk5Transform.c can run small fragments of the MAME-patched
// chunk5 binary directly (= byte-faithful replication of the per-
// vertex transform body at $7E8E..$8068 + helpers like $181A).
//
// All state is held in Cpu6502T so multiple interpreters can run
// concurrently and the caller controls the 64K address space. No
// I/O hooks, no SmartPort, no display hardware -- caller provides
// raw RAM and runs the CPU until PC reaches a configured stop
// address, or unknown opcode is hit.
#ifndef CPU6502_H
#define CPU6502_H
#include <stdbool.h>
#include <stdint.h>
typedef struct Cpu6502T {
uint8_t *mem; // 64K RAM
uint16_t pc;
uint8_t a;
uint8_t x;
uint8_t y;
uint8_t s; // stack pointer
uint8_t flagN;
uint8_t flagV;
uint8_t flagD;
uint8_t flagI;
uint8_t flagZ;
uint8_t flagC;
bool unknownOp; // set when step() hits an unimplemented opcode
uint8_t lastOp; // last opcode executed (for diagnostics)
uint16_t lastOpPc; // PC where lastOp was fetched
// Per-instruction trace hook (NULL = disabled).
void (*traceFn)(struct Cpu6502T *cpu, void *userData);
void *traceUserData;
} Cpu6502T;
// Initialise A/X/Y/S to 0, flags cleared, mem set to caller's
// buffer.
void cpu6502Init(Cpu6502T *cpu, uint8_t *mem);
// Single instruction step.
void cpu6502Step(Cpu6502T *cpu);
// Push a 16-bit return address (high then low) onto the stack so
// the next RTS pops back to (return_addr + 1). Mirrors what JSR
// does: pushes pc-1 of the instruction after JSR.
void cpu6502PushReturn(Cpu6502T *cpu, uint16_t returnAfter);
// Run starting at `entry` until PC reaches `stopPc` or an unknown
// opcode trips `cpu->unknownOp`. `maxSteps` bounds the work in
// case of a runaway loop (set to 1000000 for transform body).
// Returns true on clean halt at stopPc.
bool cpu6502Run(Cpu6502T *cpu, uint16_t entry, uint16_t stopPc, int maxSteps);
// Hook callback invoked BEFORE the instruction at `hookPc` executes.
// If `cb` returns true, the hook handled the instruction (e.g. by
// popping a return address and updating PC); the interpreter skips
// the normal step. Use to intercept JSR targets and emulate them
// in C (chunk5 DrawColorLine -> port renderer, etc.).
typedef bool (*Cpu6502HookFn)(struct Cpu6502T *cpu, void *userData);
bool cpu6502RunWithHook(Cpu6502T *cpu, uint16_t entry, uint16_t stopPc,
uint16_t hookPc, Cpu6502HookFn cb, void *userData,
int maxSteps);
// Multi-hook variant. Each entry maps a PC to its handler. The
// interpreter checks PC against each entry on every step (linear
// scan; intended for small N). Same return convention as
// cpu6502RunWithHook.
typedef struct Cpu6502HookT {
uint16_t pc;
Cpu6502HookFn cb;
void *userData;
} Cpu6502HookT;
bool cpu6502RunWithHooks(Cpu6502T *cpu, uint16_t entry, uint16_t stopPc,
const Cpu6502HookT *hooks, int nHooks,
int maxSteps);
// Per-instruction trace callback. If set on a Cpu6502T, fires
// before EVERY instruction executes. Receives pc + opcode + A/X/Y.
// Set to NULL to disable.
typedef void (*Cpu6502TraceFn)(struct Cpu6502T *cpu, void *userData);
void cpu6502SetTrace(Cpu6502T *cpu, Cpu6502TraceFn fn, void *userData);
#endif