94 lines
3.5 KiB
C
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
|