Documentation ¶
Overview ¶
Package rewind coordinates the periodic snapshotting of the emulation state. A previously seen frame can be returned to with the GotoFrame() function. If the requested frame is not in the history then the nearest frame that is will be used. The GotoLast() function will move the emulation to the last frame, whatever that might be.
The frequency at which snapshots are made is definable. Frames that are in between the snapshots can still be plumbed in, the rewind package handling the interleaving by running the emulation for the missing period.
In fact, the emulation is run even when the rewind package is set to snapshot every frame (a frequency of one) in order to generate the image data (storing the image data is memory wasteful). For this to work, the Rewind type is initialised with a reference to to the Runner interface. Implementations of the Runner interface should loop until frame, scanline, clock are matched (or the nearest point, depending on use case).
Regular emulation loops (ie. not catch-up loop of the Runner interface) must call RecordFrameState() after every CPU instruction to catch frame boundaries as early as possible. The rewind package will take the snapshot when it notices a new frame has started.
The RecordExecutionState() function can be called to force a snapshot to be taken at any time. This should probably only ever be used when the emulation is paused. The rewind package will delete an execution snapshot when the next snapshot is taken (meaning that there is only ever one execution state in the history at any one time and that it will be at the end).
Snapshots are stored in frame order from the splice point. The splice point will be wherever the snapshot history has been rewound to. For example, in a history of length 100 frames: the emulation has rewound back to frame 50. When the emulation is resumed, snapshots will be added at this point. The previous history of frames 51 to 100 will be lost.
Reset and Boundary snapshots are special splice points that only ever occur once and at the beginning of the history. Reset occurs only when the Reset() function is called and is intended to be called whenver the VCS is power cycled (not the reset switch).
The Boundary snapshot occurs when history has been cleared for some other reason. This was added to better support PlusROM cartridges and to ensure that network events are not replayed. The rewind package will add the boundary snapshot (to an empty history) automatically whenever the RewindBoundary() function from the attached cartridge returns true.
One of the weaknesses of the rewind package currently is the absence of any input replay. This might be particularly noticeable with large snapshot frequencies. Future versions of the package will record and replay input.
Index ¶
- func Plumb(vcs *hardware.VCS, state *State, fromDifferentEmulation bool)
- type PokeHook
- type Preferences
- type Rewind
- func (r *Rewind) AddTimelineCounter(ctr TimelineCounter)
- func (r *Rewind) GetComparisonState() *State
- func (r *Rewind) GetCurrentState() *State
- func (r *Rewind) GetState(frame int) *State
- func (r *Rewind) GetTimeline() Timeline
- func (r *Rewind) GotoCoords(toCoords coords.TelevisionCoords) error
- func (r *Rewind) GotoFrame(frame int) error
- func (r *Rewind) GotoLast() error
- func (r *Rewind) NewFrame(frameInfo television.FrameInfo) error
- func (r *Rewind) RecordExecutionCoords()
- func (r *Rewind) RecordState()
- func (r *Rewind) RerunLastNFrames(frames int) error
- func (r *Rewind) Reset()
- func (r *Rewind) RunPoke(from *State, to *State, poke PokeHook) error
- func (r *Rewind) SearchMemoryWrite(tgt *State, addr uint16, value uint8, valueMask uint8) (*State, error)
- func (r *Rewind) SearchRegisterWrite(tgt *State, reg rune, value uint8, valueMask uint8) (*State, error)
- func (r *Rewind) SetComparison()
- func (r *Rewind) String() string
- type Runner
- type State
- type Timeline
- type TimelineCounter
- type TimelineCounts
- type TimelineRatios
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Preferences ¶
type Preferences struct { // whether to apply the high mirror bits to the displayed address MaxEntries prefs.Int Freq prefs.Int // contains filtered or unexported fields }
func (*Preferences) Load ¶
func (p *Preferences) Load() error
Load disassembly preferences and apply to the current disassembly.
func (*Preferences) Save ¶
func (p *Preferences) Save() error
Save current disassembly preferences to disk.
func (*Preferences) SetDefaults ¶ added in v0.16.0
func (p *Preferences) SetDefaults()
SetDefaults reverts all settings to default values.
func (*Preferences) String ¶
func (p *Preferences) String() string
type Rewind ¶
type Rewind struct { // prefs for the rewind system Prefs *Preferences // contains filtered or unexported fields }
Rewind contains a history of machine states for the emulation.
func (*Rewind) AddTimelineCounter ¶ added in v0.15.0
func (r *Rewind) AddTimelineCounter(ctr TimelineCounter)
AddTimelineCounter to the rewind system. Augments Timeline information that would otherwisde be awkward to gather.
Only one timeline counter can be used at any one time (ie. subsequent calls to AddTimelineCounter() will override previous calls.)
func (*Rewind) GetComparisonState ¶ added in v0.15.0
GetComparisonState gets a reference to current comparison point. This is not a copy of the state but the actual state.
func (*Rewind) GetCurrentState ¶ added in v0.10.1
GetCurrentState returns a temporary snapshot of the current state.
func (*Rewind) GetState ¶ added in v0.15.0
GetState returns a copy for the nearest state for the indicated frame.
func (*Rewind) GetTimeline ¶ added in v0.15.0
GetTimeline returns a copy of the current Timeline. Checks integrity of the timeline and will cause the program to panic if it is insane.
func (*Rewind) GotoCoords ¶ added in v0.15.0
func (r *Rewind) GotoCoords(toCoords coords.TelevisionCoords) error
GotoCoords moves emulation to specified frame/scanline/clock "coordinates".
func (*Rewind) GotoFrame ¶
GotoFrame is a special case of GotoCoords that requires the frame number only.
func (*Rewind) GotoLast ¶
GotoLast goes to the last entry in the rewind history. It handles situations when the last entry is an execution state.
func (*Rewind) NewFrame ¶
func (r *Rewind) NewFrame(frameInfo television.FrameInfo) error
NewFrame is in an implementation of television.FrameTrigger.
func (*Rewind) RecordExecutionCoords ¶ added in v0.15.0
func (r *Rewind) RecordExecutionCoords()
RecordExecutionCoords records the coordinates of the current execution state.
func (*Rewind) RecordState ¶ added in v0.15.0
func (r *Rewind) RecordState()
RecordState should be called after every CPU instruction. A new state will be recorded if the current rewind policy agrees.
func (*Rewind) RerunLastNFrames ¶ added in v0.15.0
RerunLastNFrames runs the emulation from the a point N frames in the past to the current state.
func (*Rewind) Reset ¶
func (r *Rewind) Reset()
Reset rewind system removes all entries and takes a snapshot of the execution state. Resets timeline too.
This should be called whenever a new cartridge is attached to the emulation.
func (*Rewind) RunPoke ¶ added in v0.15.0
RunPoke will the run the VCS from one state to another state applying the supplied PokeHook to the from State
func (*Rewind) SearchMemoryWrite ¶ added in v0.10.1
func (r *Rewind) SearchMemoryWrite(tgt *State, addr uint16, value uint8, valueMask uint8) (*State, error)
SearchMemoryWrite runs an emulation between two states looking for the instance when the address is written to with the value (valueMask is applied to mask specific bits)
The supplied target state is the upper limit of the search. The lower limit of the search is one frame before the target State.
The supplied address will be normalised.
Returns the most recent State at which the memory write was found. If a more recent address write is found but not the correct value, then no state is returned.
func (*Rewind) SearchRegisterWrite ¶ added in v0.10.1
func (r *Rewind) SearchRegisterWrite(tgt *State, reg rune, value uint8, valueMask uint8) (*State, error)
SearchMemoryWrite runs an emulation between two states looking for the instance when the register is written to with the value (valueMask is applied to mask specific bits)
The supplied target state is the upper limit of the search. The lower limit of the search is one frame before the target State.
Returns the most recent State at which the register write was found. If a more recent register write is found but not the correct value, then no state is returned.
func (*Rewind) SetComparison ¶
func (r *Rewind) SetComparison()
SetComparison points comparison to the most recent rewound entry.
type Runner ¶
type Runner interface { // CatchupLoop should loop until the frame/scanline/clock coordinates are // met. f should be called periodically, ideally every video cycle. // // When implementating the CatchupLoop(), care should be takan about what // to do for example, if the scaline/clock coordinates do no exist on the // specified frame. Either stop when the frame becomes too large or don't // request the rewind in the first place. Such details are outside the // scope of the rewind package however. CatchUpLoop(coords.TelevisionCoords) error }
Runner provides the rewind package the opportunity to run the emulation.
type State ¶
type State struct { CPU *cpu.CPU Mem *memory.Memory RIOT *riot.RIOT TIA *tia.TIA TV *television.State // contains filtered or unexported fields }
State contains pointers to areas of the VCS emulation. They can be read for reference.
type Timeline ¶ added in v0.15.0
type Timeline struct { FrameNum []int TotalScanlines []int Counts []TimelineCounts Ratios []TimelineRatios // peripheral input (including the panel). entry is true if the peripheral // was "active" at the end of a frame LeftPlayerInput []bool RightPlayerInput []bool PanelInput []bool // These two "available" fields state the earliest and latest frames that // are available in the rewind history. // // The earliest information in the Timeline array fields may be different. AvailableStart int AvailableEnd int }
Timeline provides a summary of the current state of the rewind system.
Useful for GUIs for example, to present the range of frame numbers that are available in the rewind history.
type TimelineCounter ¶ added in v0.15.0
type TimelineCounter interface {
TimelineCounts() TimelineCounts
}
TimelineCounter implementations provide system information for the timeline that would otherwise be awkward to collate.
Implementations should reset counts in time for the next call to TimelineCounts().
type TimelineCounts ¶ added in v0.15.0
TimelineCounts is returned by a TimelineCounter implementation. The value should be updated every *video* cycle. Users can divide by three to get the color-clock count.