Files
SplitBit-Emulator/Source/Emulator/utility.h
T
AnachronautandClaude Opus 5 a163c670d0 A demo recorder: --record-pad writes what --pad reads
One byte a frame, in exactly the format the player takes, so a recording
needs no conversion and there is no second format to keep in step. That
symmetry is the feature, and it makes the strongest form of the claim
testable: a recording is made OF a playback, and the bytes coming out have
to be the bytes that went in.

It exists because some inputs cannot sensibly be written by hand. Flying a
lander from one base to another is a few hundred frames of steering that
has to arrive somewhere eight cells wide, and several attempts at
authoring one got within two columns and no closer. That is a piloting
exercise rather than a test. Playing it once and keeping what happened is
the answer.

A BYTE FOR EVERY FRAME, written inside the loop that advances the
recordings rather than after it, so a machine that jumped several frames
at once still writes one for each. A recording is a timeline: one that
skipped the frames nobody looked at would play back faster than it was
flown.

What is recorded is what the DEVICE WOULD REPORT, not the live state - a
recording of a playback that wrote the live state would be a file of
noughts. And it is flushed as it goes, because a recording is usually
stopped by whoever is playing rather than by the program ending, and a
demo lost to a buffer is a demo flown twice.

Tests/replay.sh is where this and whatever follows it are checked. Twelve
scripts now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
2026-09-03 12:38:43 -04:00

66 lines
2.8 KiB
C

// utility.h
// Utilities for the SplitBit CPU Emulator
// Written by Anachronaut
// 10/15/2024
#ifndef UTILITY_H
#define UTILITY_H
#include <stdint.h>
#include "io.h"
#include "cpu.h"
// Results of reading the command line.
#define OPTIONS_OK 0 // Carry on and run the program.
#define OPTIONS_HELP 1 // The user asked for help, so stop, but not because of an error.
#define OPTIONS_ERROR 2 // The command line was no good, stop and complain.
// As many as the machine has pads.
#define PAD_DRIVE_COUNT 4
typedef struct {
uint8_t debug; // Step one instruction at a time, printing the registers.
uint8_t fast; // Ignore the cycle rate and run as fast as the host allows.
unsigned long cycles; // Stop after this many cycles. Zero means run until the program halts.
unsigned long diskCycles; // How long a block move takes. Zero is instant, and the default.
// ---- The drives, in the order they were named ----
//
// --disk given more than once fills them in turn, so the first is drive 0 and the machine
// has as many as were asked for. One name is the ordinary case and reads exactly as it
// did when there could only be one.
const char *disk; // Disk image to attach, or NULL for a machine with no disk.
const char *disks[DISK_DRIVE_COUNT];
int diskCount;
// A drive of this many blocks made of memory, taking the next drive number after the
// images above. Zero for a machine without one.
unsigned long ramDisk;
uint8_t writeProtect; // Attach the disk read only, the way a tab on a floppy would.
const char *screen; // Where to save a picture of the screen when the machine stops.
const char *keyboard; // Feed the console from this file as a keyboard, not a terminal.
const char *sound; // Where to save the samples the machine made, as raw 16 bit.
// ---- A controller made of a file ----
//
// One byte a frame, each byte the buttons held during it. Voyager reads a real pad, and
// its own tests run headless with nobody holding anything - so without this the device
// would be exercised only by somebody playing, which is exactly the state the console's
// line editing was in when it broke twice in two days.
const char *pads[PAD_DRIVE_COUNT];
int padCount; // --pad given more than once fills them in turn, like --disk.
// Where to write what each pad held, one byte a frame, in the format --pad reads.
const char *padRecord[PAD_DRIVE_COUNT];
int padRecordCount;
} EmulatorOptions;
uint8_t parseOptions(int argc, char *argv[], EmulatorOptions *options);
void printHelp(const char *programName);
uint8_t loadFile(const char *path, uint8_t *Program, uint8_t *Data);
void bootStrap(uint8_t *Program, uint8_t *Data);
void printRegisters(CPURegisters *cpu, uint8_t *Program, uint8_t *Data);
#endif // UTILITY_H