removed InstructionBoundary() interface and television.ReqState()

Instruction boundaries can be inferred by the debugging input loop,
which is the only place it is requred. reworked GetAdjustedCoords() in
the televsion package (now called AdjCoords()) to cope with this.

ReqState() is totally replaced by GetCoords()
This commit is contained in:
JetSetIlly 2021-10-23 07:31:06 +01:00
parent 63b188b997
commit 31138f16f3
25 changed files with 163 additions and 231 deletions

View file

@ -38,7 +38,8 @@ import (
"github.com/jetsetilly/gopher2600/hardware/riot/ports"
"github.com/jetsetilly/gopher2600/hardware/riot/ports/controllers"
"github.com/jetsetilly/gopher2600/hardware/riot/ports/plugging"
"github.com/jetsetilly/gopher2600/hardware/television/signal"
"github.com/jetsetilly/gopher2600/hardware/television"
"github.com/jetsetilly/gopher2600/hardware/television/coords"
"github.com/jetsetilly/gopher2600/linter"
"github.com/jetsetilly/gopher2600/logger"
"github.com/jetsetilly/gopher2600/patch"
@ -198,14 +199,14 @@ func (dbg *Debugger) processTokens(tokens *commandline.Tokens) error {
dbg.haltImmediately = true
case cmdStep:
adj := 1
adjAmount := 1
back := false
if tk, ok := tokens.Get(); ok {
switch tk {
case "BACK":
back = true
adj *= -1
adjAmount *= -1
case "OVER":
// if next expected opcode is JSR then add a volatile breakpoint to the
@ -229,33 +230,37 @@ func (dbg *Debugger) processTokens(tokens *commandline.Tokens) error {
mode = strings.ToUpper(mode)
if back {
var req signal.StateAdj
var instruction bool
var adj television.Adj
switch mode {
case "":
// continue with current quantum state
if dbg.stepQuantum == QuantumInstruction {
req = signal.AdjInstruction
instruction = true
} else {
req = signal.AdjClock
adj = television.AdjClock
}
case "INSTRUCTION":
dbg.stepQuantum = QuantumInstruction
req = signal.AdjInstruction
instruction = true
case "VIDEO":
dbg.stepQuantum = QuantumVideo
req = signal.AdjClock
adj = television.AdjClock
case "SCANLINE":
req = signal.AdjScanline
adj = television.AdjScanline
case "FRAME":
req = signal.AdjFramenum
adj = television.AdjFrame
default:
return curated.Errorf("unknown STEP BACK mode (%s)", mode)
}
coords, err := dbg.vcs.TV.GetAdjustedCoords(req, adj, true)
if err != nil {
return err
var coords coords.TelevisionCoords
if instruction {
coords = dbg.lastCPUboundary
} else {
coords = dbg.vcs.TV.AdjCoords(adj, adjAmount)
}
dbg.setState(emulation.Rewinding)

View file

@ -40,6 +40,7 @@ import (
"github.com/jetsetilly/gopher2600/hardware/riot/ports/plugging"
"github.com/jetsetilly/gopher2600/hardware/riot/ports/savekey"
"github.com/jetsetilly/gopher2600/hardware/television"
"github.com/jetsetilly/gopher2600/hardware/television/coords"
"github.com/jetsetilly/gopher2600/logger"
"github.com/jetsetilly/gopher2600/reflection"
"github.com/jetsetilly/gopher2600/rewind"
@ -66,6 +67,9 @@ type Debugger struct {
lastBank mapper.BankInfo
lastResult *disassembly.Entry
// the television coords of the last CPU instruction
lastCPUboundary coords.TelevisionCoords
// gui, terminal and controllers
gui gui.GUI
term terminal.Terminal
@ -242,9 +246,6 @@ func NewDebugger(tv *television.Television, scr gui.GUI, term terminal.Terminal,
dbg.vcs.TV.AddFrameTrigger(dbg.Rewind)
dbg.vcs.TV.AddFrameTrigger(dbg.ref)
// plug TV BoundaryTrigger into CPU
dbg.vcs.CPU.AddBoundaryTrigger(dbg.vcs.TV)
// halting coordination
dbg.halting, err = newHaltCoordination(dbg)
if err != nil {

View file

@ -21,7 +21,6 @@ import (
"github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/debugger/terminal/commandline"
"github.com/jetsetilly/gopher2600/hardware/television/signal"
)
// targetValue represents the underlying value of the target. for example in
@ -138,7 +137,7 @@ func parseTarget(dbg *Debugger, tokens *commandline.Tokens) (*target, error) {
trg = &target{
label: "Frame",
value: func() targetValue {
return dbg.vcs.TV.GetState(signal.ReqFramenum)
return dbg.vcs.TV.GetCoords().Frame
},
instructionBoundary: false,
}
@ -147,7 +146,7 @@ func parseTarget(dbg *Debugger, tokens *commandline.Tokens) (*target, error) {
trg = &target{
label: "Scanline",
value: func() targetValue {
return dbg.vcs.TV.GetState(signal.ReqScanline)
return dbg.vcs.TV.GetCoords().Scanline
},
instructionBoundary: false,
}
@ -156,7 +155,7 @@ func parseTarget(dbg *Debugger, tokens *commandline.Tokens) (*target, error) {
trg = &target{
label: "Clock",
value: func() targetValue {
return dbg.vcs.TV.GetState(signal.ReqClock)
return dbg.vcs.TV.GetCoords().Clock
},
instructionBoundary: false,
}

View file

@ -125,6 +125,9 @@ func (dbg *Debugger) catchupLoop(inputter terminal.Input) error {
for !ended {
dbg.lastBank = dbg.vcs.Mem.Cart.GetBank(dbg.vcs.CPU.PC.Address())
// coords of CPU instruction before calling vcs.Step()
dbg.lastCPUboundary = dbg.vcs.TV.GetCoords()
err := dbg.vcs.Step(callback)
if err != nil {
return err
@ -435,6 +438,9 @@ func (dbg *Debugger) step(inputter terminal.Input, catchup bool) error {
// to happen before we call the VCS.Step() function
dbg.lastBank = dbg.vcs.Mem.Cart.GetBank(dbg.vcs.CPU.PC.Address())
// coords of CPU instruction before calling vcs.Step()
dbg.lastCPUboundary = dbg.vcs.TV.GetCoords()
// not using the err variable because we'll clobber it before we
// get to check the result of VCS.Step()
stepErr := dbg.vcs.Step(callback)

View file

@ -56,7 +56,7 @@ func NewVideo(tv *television.Television) (*Video, error) {
// length of pixels array contains enough room for the previous frames digest value
l := len(dig.digest)
l += television.MaxSignalHistory * pixelDepth
l += specification.AbsoluteMaxClks * pixelDepth
// allocate enough pixels for entire frame
dig.pixels = make([]byte, l)

View file

@ -22,8 +22,8 @@ import (
"github.com/jetsetilly/gopher2600/hardware"
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge"
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper"
"github.com/jetsetilly/gopher2600/hardware/television"
"github.com/jetsetilly/gopher2600/hardware/television/coords"
"github.com/jetsetilly/gopher2600/hardware/television/signal"
)
// CoProcessor is used to handle the disassembly of instructions from an
@ -99,7 +99,7 @@ func (cop *CoProcessor) Start() {
// have been called on the last CPU cycle of the instruction that triggers
// the coprocessor reset. the TV will not have moved onto the beginning of
// the next instruction yet so we must figure it out here
cop.lastStart, _ = cop.vcs.TV.GetAdjustedCoords(signal.AdjCPUCycle, 1, false)
cop.lastStart = cop.vcs.TV.AdjCoords(television.AdjCPUCycle, 1)
}
cop.lastExecution = cop.lastExecution[:0]

View file

@ -406,7 +406,7 @@ func (scr *screen) Reflect(ref []reflection.ReflectedVideoStep) error {
// array but if we do want to make sure then something like the condition
// below would be good.
//
if len(ref) != television.MaxSignalHistory {
if len(ref) != specification.AbsoluteMaxClks {
panic("reflected entries not the same length as reflection buffer")
}

View file

@ -19,7 +19,6 @@ import (
"fmt"
"github.com/inkyblackness/imgui-go/v4"
"github.com/jetsetilly/gopher2600/hardware/television/signal"
"github.com/jetsetilly/gopher2600/hardware/television/specification"
)
@ -237,7 +236,7 @@ func (win *winTimeline) drawTimeline() {
// comparison frame indicator
if win.img.lz.Rewind.Comparison != nil {
fr := win.img.lz.Rewind.Comparison.TV.GetState(signal.ReqFramenum) - rewindOffset
fr := win.img.lz.Rewind.Comparison.TV.GetCoords().Frame - rewindOffset
if fr < 0 {
// draw triangle indicating that the comparison frame is not

View file

@ -1,22 +0,0 @@
// This file is part of Gopher2600.
//
// Gopher2600 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Gopher2600 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Gopher2600. If not, see <https://www.gnu.org/licenses/>.
package cpu
// BoundaryTrigger functions are called at key points in the CPU execution.
type BoundaryTrigger interface {
// InstructionBoundary is called at the start of each new CPU instruction.
InstructionBoundary()
}

View file

@ -73,9 +73,6 @@ type CPU struct {
// otherwise be considered an error. Resets to false on every call to
// ExecuteInstruction()
Interrupted bool
// list of BoundaryTriggers implementations to consult
boundaryTriggers []BoundaryTrigger
}
// NewCPU is the preferred method of initialisation for the CPU structure. Note
@ -96,12 +93,6 @@ func NewCPU(prefs *preferences.Preferences, mem bus.CPUBus) *CPU {
}
}
// AddPixelRenderer registers an implementation of BoundaryTrigger. Multiple
// implemntations can be added.
func (mc *CPU) AddBoundaryTrigger(b BoundaryTrigger) {
mc.boundaryTriggers = append(mc.boundaryTriggers, b)
}
// Snapshot creates a copy of the CPU in its current state.
func (mc *CPU) Snapshot() *CPU {
n := *mc
@ -538,11 +529,6 @@ func (mc *CPU) ExecuteInstruction(cycleCallback func() error) error {
return nil
}
// process all boundaryTriggers
for _, b := range mc.boundaryTriggers {
b.InstructionBoundary()
}
// prepare new round of results
mc.LastResult.Reset()
mc.LastResult.Address = mc.PC.Address()

View file

@ -17,7 +17,6 @@ package hardware
import (
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/hardware/television/signal"
)
// checking continue condition every Run iteration is too frequent. A modest
@ -85,7 +84,7 @@ func (vcs *VCS) RunForFrameCount(numFrames int, continueCheck func(frame int) (e
continueCheck = func(frame int) (emulation.State, error) { return emulation.Running, nil }
}
frameNum := vcs.TV.GetState(signal.ReqFramenum)
frameNum := vcs.TV.GetCoords().Frame
targetFrame := frameNum + numFrames
state := emulation.Running
@ -95,7 +94,7 @@ func (vcs *VCS) RunForFrameCount(numFrames int, continueCheck func(frame int) (e
return err
}
frameNum = vcs.TV.GetState(signal.ReqFramenum)
frameNum = vcs.TV.GetCoords().Frame
state, err = continueCheck(frameNum)
if err != nil {

View file

@ -0,0 +1,85 @@
// This file is part of Gopher2600.
//
// Gopher2600 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Gopher2600 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Gopher2600. If not, see <https://www.gnu.org/licenses/>.
package television
import (
"github.com/jetsetilly/gopher2600/hardware/television/coords"
"github.com/jetsetilly/gopher2600/hardware/television/specification"
)
// AdjCoords returns a coords.TelevisionCoords with the current coords adjusted
// by the specified amount.
func (tv *Television) AdjCoords(adj Adj, amount int) coords.TelevisionCoords {
coords := tv.GetCoords()
switch adj {
case AdjCPUCycle:
// adjusting by CPU cycle is the same as adjusting by video cycle
// accept to say that a CPU cycle is the equivalent of 3 video cycles
amount *= 3
fallthrough
case AdjClock:
coords.Clock += amount
if coords.Clock >= specification.ClksScanline {
coords.Clock -= specification.ClksScanline
coords.Scanline++
} else if coords.Clock < 0 {
coords.Clock += specification.ClksScanline
coords.Scanline--
}
if coords.Scanline > tv.state.frameInfo.TotalScanlines {
coords.Scanline -= tv.state.frameInfo.TotalScanlines
coords.Frame++
} else if coords.Scanline < 0 {
coords.Scanline += tv.state.frameInfo.TotalScanlines
coords.Frame--
}
case AdjScanline:
coords.Clock = 0
coords.Scanline += amount
if coords.Scanline > tv.state.frameInfo.TotalScanlines {
coords.Scanline -= tv.state.frameInfo.TotalScanlines
coords.Frame++
} else if coords.Scanline < 0 {
coords.Scanline += tv.state.frameInfo.TotalScanlines
coords.Frame--
}
case AdjFrame:
coords.Clock = 0
coords.Scanline = 0
coords.Frame += amount
}
// zero values if frame is less than zero
if coords.Frame < 0 {
coords.Frame = 0
coords.Scanline = 0
coords.Clock = 0
}
return coords
}
// Adj is used to specify adjustment scale for the ReqAdjust() function.
type Adj int
// List of valid Adj values.
const (
AdjFrame Adj = iota
AdjScanline
AdjCPUCycle
AdjClock
)

View file

@ -42,7 +42,9 @@
// the current incoming TV signal. For debugging purposes, the framerate can
// also be set to a specific value
//
// Framesize adaptation is also handled by the television package.
// Framesize adaptation is also handled by the television package. Current
// information about the frame can be acquired with GetFrameInfo(). FrameInfo
// will also be sent to the PixelRenderers as appropriate.
//
// Screen Rolling
//

View file

@ -17,7 +17,6 @@ package television
import (
"github.com/jetsetilly/gopher2600/hardware/television/signal"
"github.com/jetsetilly/gopher2600/hardware/television/specification"
)
// PixelRenderer implementations displays, or otherwise works with, visual
@ -152,9 +151,6 @@ type AudioMixer interface {
Reset()
}
// MaxSignalHistory is the absolute maximum number of entries in a signal history for an entire frame.
const MaxSignalHistory = specification.AbsoluteMaxClks
// VCSReturnChannel is used to send information from the TV back to the parent
// console. Named because I think of it as being similar to the Audio Return
// Channel (ARC) present in modern TVs.

View file

@ -17,7 +17,11 @@
// implementation.
package signal
import "strings"
import (
"strings"
"github.com/jetsetilly/gopher2600/hardware/television/coords"
)
// ColorSignal represents the signal that is sent from the VCS to the television.
type ColorSignal uint8
@ -75,36 +79,13 @@ func (a SignalAttributes) String() string {
return s.String()
}
// StateReq is used to identify which television attribute is being asked
// with the GetState() function.
type StateReq int
// List of valid state requests.
const (
ReqFramenum StateReq = iota
ReqScanline
ReqClock
)
// StateAdj is used to specify adjustment scale for the ReqAdjust() function.
type StateAdj int
// List of valid adjustment scales.
const (
AdjFramenum StateAdj = iota
AdjScanline
AdjInstruction
AdjCPUCycle
AdjClock
)
// TelevisionTIA exposes only the functions required by the TIA.
type TelevisionTIA interface {
Signal(SignalAttributes) error
GetState(StateReq) int
GetCoords() coords.TelevisionCoords
}
// TelevisionSprite exposes only the functions required by the video sprites.
type TelevisionSprite interface {
GetState(StateReq) int
GetCoords() coords.TelevisionCoords
}

View file

@ -98,19 +98,6 @@ func (s *State) Snapshot() *State {
return &n
}
// GetState Returns information about the current state of the signal.
func (s *State) GetState(request signal.StateReq) int {
switch request {
case signal.ReqFramenum:
return s.frameNum
case signal.ReqScanline:
return s.scanline
case signal.ReqClock:
return s.clock - specification.ClksHBlank
}
panic(fmt.Sprintf("television: unhandled tv state request (%v)", request))
}
// GetCoords returns an instance of coords.TelevisionCoords.
func (s *State) GetCoords() coords.TelevisionCoords {
return coords.TelevisionCoords{
@ -177,7 +164,7 @@ func NewTelevision(spec string) (*Television, error) {
tv := &Television{
reqSpecID: strings.ToUpper(spec),
state: &State{},
signals: make([]signal.SignalAttributes, MaxSignalHistory),
signals: make([]signal.SignalAttributes, specification.AbsoluteMaxClks),
}
// initialise frame rate limiter
@ -416,7 +403,7 @@ func (tv *Television) Signal(sig signal.SignalAttributes) error {
tv.state.lastSignal = sig
// record signal history
if tv.currentSignalIdx >= MaxSignalHistory {
if tv.currentSignalIdx >= len(tv.signals) {
return tv.renderSignals()
}
@ -681,8 +668,7 @@ func (tv *Television) GetReqSpecID() string {
return tv.reqSpecID
}
// GetFrameInfo returns the television's current frame information. FPS and
// RefreshRate is returned by GetReqFPS().
// GetFrameInfo returns the television's current frame information.
func (tv *Television) GetFrameInfo() FrameInfo {
return tv.state.frameInfo
}
@ -693,92 +679,7 @@ func (tv *Television) GetLastSignal() signal.SignalAttributes {
return tv.state.lastSignal
}
// GetState returns state information for the TV.
func (tv *Television) GetState(request signal.StateReq) int {
return tv.state.GetState(request)
}
// GetCoords returns an instance of coords.TelevisionCoords.
func (tv *Television) GetCoords() coords.TelevisionCoords {
return tv.state.GetCoords()
}
// GetAdjustedCoords returns a coords.TelevisionCoords with the current coords
// adjusted by the specified value
//
// The reset argument instructs the function to return values that have been
// reset to zero as appropriate. So when request is ReqFramenum, the scanline
// and clock values will be zero; when request is ReqScanline, the clock value
// will be zero. It has no affect when request is ReqClock.
//
// In the case of a StateAdj of AdjCPUCycle the only allowed adjustment value
// is -1. Any other value will return an error.
func (tv *Television) GetAdjustedCoords(request signal.StateAdj, adjustment int, reset bool) (coords.TelevisionCoords, error) {
coords := tv.GetCoords()
var err error
switch request {
case signal.AdjCPUCycle:
// adjusting by CPU cycle is the same as adjusting by video cycle
// accept to say that a CPU cycle is the equivalent of 3 video cycles
adjustment *= 3
fallthrough
case signal.AdjClock:
coords.Clock += adjustment
if coords.Clock >= specification.ClksScanline {
coords.Clock -= specification.ClksScanline
coords.Scanline++
} else if coords.Clock < 0 {
coords.Clock += specification.ClksScanline
coords.Scanline--
}
if coords.Scanline > tv.state.frameInfo.TotalScanlines {
coords.Scanline -= tv.state.frameInfo.TotalScanlines
coords.Frame++
} else if coords.Scanline < 0 {
coords.Scanline += tv.state.frameInfo.TotalScanlines
coords.Frame--
}
case signal.AdjInstruction:
if adjustment != -1 {
err = curated.Errorf("television: can only adjust CPU boundary by -1")
} else {
coords.Clock = tv.state.lastCPUInstruction.Clock
coords.Scanline = tv.state.lastCPUInstruction.Scanline
coords.Frame = tv.state.lastCPUInstruction.Frame
}
case signal.AdjScanline:
if reset {
coords.Clock = 0
}
coords.Scanline += adjustment
if coords.Scanline > tv.state.frameInfo.TotalScanlines {
coords.Scanline -= tv.state.frameInfo.TotalScanlines
coords.Frame++
} else if coords.Scanline < 0 {
coords.Scanline += tv.state.frameInfo.TotalScanlines
coords.Frame--
}
case signal.AdjFramenum:
if reset {
coords.Clock = 0
coords.Scanline = 0
}
coords.Frame += adjustment
}
// zero values if frame is less than zero
if coords.Frame < 0 {
coords.Frame = 0
coords.Scanline = 0
coords.Clock = 0
}
return coords, err
}
// InstructionBoundary implements the cpu.BoundaryTrigger interface.
func (tv *Television) InstructionBoundary() {
tv.state.lastCPUInstruction = tv.state.GetCoords()
}

View file

@ -308,7 +308,7 @@ func (tia *TIA) resolveDelayedEvents() {
// adjust video elements by the number of visible pixels that have
// been consumed. adding one to the value because the tv pixel we
// want to hit has not been reached just yet
adj := tia.tv.GetState(signal.ReqClock) + 1
adj := tia.tv.GetCoords().Clock + 1
if adj > 0 {
tia.Video.RSYNC(adj)
}

View file

@ -19,7 +19,6 @@ import (
"fmt"
"strings"
"github.com/jetsetilly/gopher2600/hardware/television/signal"
"github.com/jetsetilly/gopher2600/hardware/television/specification"
"github.com/jetsetilly/gopher2600/hardware/tia/delay"
"github.com/jetsetilly/gopher2600/hardware/tia/phaseclock"
@ -327,7 +326,7 @@ func (bs *BallSprite) _futureResetPosition() {
// the pixel at which the sprite has been reset, in relation to the
// left edge of the screen
bs.ResetPixel = bs.tia.tv.GetState(signal.ReqClock)
bs.ResetPixel = bs.tia.tv.GetCoords().Clock
if bs.ResetPixel >= 0 {
// resetPixel adjusted by 1 because the tv is not yet in the correct

View file

@ -19,7 +19,6 @@ import (
"fmt"
"strings"
"github.com/jetsetilly/gopher2600/hardware/television/signal"
"github.com/jetsetilly/gopher2600/hardware/television/specification"
"github.com/jetsetilly/gopher2600/hardware/tia/delay"
"github.com/jetsetilly/gopher2600/hardware/tia/phaseclock"
@ -262,7 +261,7 @@ func (ms *MissileSprite) tick(resetToPlayer bool) bool {
ms.pclk = phaseclock.ResetValue
// missile-to-player also resets position information
ms.ResetPixel = ms.tia.tv.GetState(signal.ReqClock)
ms.ResetPixel = ms.tia.tv.GetCoords().Clock
ms.HmovedPixel = ms.ResetPixel
}
@ -391,7 +390,7 @@ func (ms *MissileSprite) resetPosition() {
func (ms *MissileSprite) _futureResetPosition() {
// the pixel at which the sprite has been reset, in relation to the
// left edge of the screen
ms.ResetPixel = ms.tia.tv.GetState(signal.ReqClock)
ms.ResetPixel = ms.tia.tv.GetCoords().Clock
if ms.ResetPixel >= 0 {
// resetPixel adjusted by 1 because the tv is not yet in the correct

View file

@ -19,7 +19,6 @@ import (
"fmt"
"strings"
"github.com/jetsetilly/gopher2600/hardware/television/signal"
"github.com/jetsetilly/gopher2600/hardware/television/specification"
"github.com/jetsetilly/gopher2600/hardware/tia/delay"
"github.com/jetsetilly/gopher2600/hardware/tia/phaseclock"
@ -461,7 +460,7 @@ func (ps *PlayerSprite) resetPosition() {
// for us.
if (*ps.tia.hsync == 16 || *ps.tia.hsync == 18) && *ps.tia.pclk == phaseclock.RisingPhi2 {
if ps.tia.rev.Prefs.RESPxHBLANK {
hblank = !revision.HeatThreshold(ps.tia.tv.GetState(signal.ReqScanline))
hblank = !revision.HeatThreshold(ps.tia.tv.GetCoords().Scanline)
}
}
@ -546,7 +545,7 @@ func (ps *PlayerSprite) resetPosition() {
func (ps *PlayerSprite) _futureResetPosition() {
// the pixel at which the sprite has been reset, in relation to the
// left edge of the screen
ps.ResetPixel = ps.tia.tv.GetState(signal.ReqClock)
ps.ResetPixel = ps.tia.tv.GetCoords().Clock
if ps.ResetPixel >= 0 {
// resetPixel adjusted by +1 because the tv is not yet in the correct.

View file

@ -27,7 +27,6 @@ import (
"github.com/jetsetilly/gopher2600/gui"
"github.com/jetsetilly/gopher2600/hardware"
"github.com/jetsetilly/gopher2600/hardware/television"
"github.com/jetsetilly/gopher2600/hardware/television/signal"
"github.com/jetsetilly/gopher2600/setup"
"github.com/jetsetilly/gopher2600/userinput"
)
@ -72,7 +71,7 @@ func Check(output io.Writer, profile Profile, includeDetail bool,
}
// get starting frame number (should be 0)
startFrame := tv.GetState(signal.ReqFramenum)
startFrame := tv.GetCoords().Frame
// run for specified period of time
runner := func() error {
@ -91,7 +90,7 @@ func Check(output io.Writer, profile Profile, includeDetail bool,
// signal parent function that 2 second leadtime has elapsed
timerChan <- false
// race condition when GetState() is called
// race condition when GetCoords() is called
time.AfterFunc(dur, func() {
timerChan <- true
})
@ -114,7 +113,7 @@ func Check(output io.Writer, profile Profile, includeDetail bool,
// leadtime has concluded. this means the performance
// measurement has begun and we should record the start
// frame.
startFrame = tv.GetState(signal.ReqFramenum)
startFrame = tv.GetCoords().Frame
default:
return emulation.Running, nil
}
@ -136,7 +135,7 @@ func Check(output io.Writer, profile Profile, includeDetail bool,
}
// get ending frame number
endFrame := vcs.TV.GetState(signal.ReqFramenum)
endFrame := vcs.TV.GetCoords().Frame
// calculate performance
numFrames := endFrame - startFrame

View file

@ -29,7 +29,6 @@ import (
"github.com/jetsetilly/gopher2600/hardware/riot/ports"
"github.com/jetsetilly/gopher2600/hardware/riot/ports/plugging"
"github.com/jetsetilly/gopher2600/hardware/television/coords"
"github.com/jetsetilly/gopher2600/hardware/television/signal"
)
type playbackEntry struct {
@ -62,14 +61,14 @@ type Playback struct {
}
func (plb Playback) String() string {
currFrame := plb.digest.GetState(signal.ReqFramenum)
currFrame := plb.digest.GetCoords().Frame
return fmt.Sprintf("%d/%d (%.1f%%)", currFrame, plb.endFrame, 100*(float64(currFrame)/float64(plb.endFrame)))
}
// EndFrame returns true if emulation has gone past the last frame of the
// playback.
func (plb Playback) EndFrame() (bool, error) {
currFrame := plb.digest.GetState(signal.ReqFramenum)
currFrame := plb.digest.GetCoords().Frame
if currFrame > plb.endFrame {
return true, nil
}

View file

@ -22,6 +22,7 @@ import (
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper"
"github.com/jetsetilly/gopher2600/hardware/television"
"github.com/jetsetilly/gopher2600/hardware/television/signal"
"github.com/jetsetilly/gopher2600/hardware/television/specification"
"github.com/jetsetilly/gopher2600/logger"
"github.com/jetsetilly/gopher2600/rewind"
)
@ -50,7 +51,7 @@ type Gatherer struct {
func NewGatherer(vcs *hardware.VCS) *Gatherer {
return &Gatherer{
vcs: vcs,
history: make([]ReflectedVideoStep, television.MaxSignalHistory),
history: make([]ReflectedVideoStep, specification.AbsoluteMaxClks),
}
}

View file

@ -27,7 +27,6 @@ import (
"github.com/jetsetilly/gopher2600/hardware/riot"
"github.com/jetsetilly/gopher2600/hardware/television"
"github.com/jetsetilly/gopher2600/hardware/television/coords"
"github.com/jetsetilly/gopher2600/hardware/television/signal"
"github.com/jetsetilly/gopher2600/hardware/television/specification"
"github.com/jetsetilly/gopher2600/hardware/tia"
"github.com/jetsetilly/gopher2600/logger"
@ -94,7 +93,7 @@ func (s State) String() string {
case levelAdhoc:
return "c"
}
return fmt.Sprintf("%d", s.TV.GetState(signal.ReqFramenum))
return fmt.Sprintf("%d", s.TV.GetCoords().Frame)
}
// an overhead of two is required. (1) to accommodate the end index required for
@ -321,7 +320,7 @@ func (r *Rewind) RecordFrameState() {
if r.boundaryNextFrame {
r.boundaryNextFrame = false
r.reset(levelBoundary)
logger.Logf("rewind", "boundary added at frame %d", r.vcs.TV.GetState(signal.ReqFramenum))
logger.Logf("rewind", "boundary added at frame %d", r.vcs.TV.GetCoords().Frame)
return
}
@ -395,7 +394,7 @@ func (r *Rewind) append(s *State) {
}
// splice timeline at current frame number
r.timeline.splice(r.vcs.TV.GetState(signal.ReqFramenum))
r.timeline.splice(r.vcs.TV.GetCoords().Frame)
}
// setContinuePoint sets the splice point to the supplied index. the emulation
@ -558,13 +557,13 @@ func (r *Rewind) findFrameIndex(frame int) (idx int, fr int, last bool) {
// then plumb in the nearest entry
// is requested frame too old (ie. before the start of the array)
fn := r.entries[s].TV.GetState(signal.ReqFramenum)
fn := r.entries[s].TV.GetCoords().Frame
if sf < fn {
return s, fn + 1, false
}
// is requested frame too new (ie. past the end of the array)
fn = r.entries[e].TV.GetState(signal.ReqFramenum)
fn = r.entries[e].TV.GetCoords().Frame
if sf >= fn {
e--
if e < 0 {
@ -580,7 +579,7 @@ func (r *Rewind) findFrameIndex(frame int) (idx int, fr int, last bool) {
// binary search. if start (lower) is greater then end (upper) then check
// which half of the circular array to concentrate on.
if r.start > e {
fn := r.entries[len(r.entries)-1].TV.GetState(signal.ReqFramenum)
fn := r.entries[len(r.entries)-1].TV.GetCoords().Frame
if sf <= fn {
e = len(r.entries) - 1
} else {
@ -596,7 +595,7 @@ func (r *Rewind) findFrameIndex(frame int) (idx int, fr int, last bool) {
for s <= e {
idx := (s + e) / 2
fn := r.entries[idx].TV.GetState(signal.ReqFramenum)
fn := r.entries[idx].TV.GetCoords().Frame
// check for match, taking into consideration the gaps introduced by
// the frequency value
@ -625,7 +624,7 @@ type PokeHook func(res *State) error
// RunFromState will the run the VCS from one state to another state.
func (r *Rewind) RunFromState(from *State, to *State, poke PokeHook) error {
ff := from.TV.GetState(signal.ReqFramenum)
ff := from.TV.GetCoords().Frame
idx, _, _ := r.findFrameIndex(ff)
if poke != nil {
@ -647,7 +646,7 @@ func (r *Rewind) RunFromState(from *State, to *State, poke PokeHook) error {
// the current state.
func (r *Rewind) RerunLastNFrames(frames int) error {
to := r.GetCurrentState()
ff := to.TV.GetState(signal.ReqFramenum) - frames
ff := to.TV.GetCoords().Frame
if ff < 0 {
ff = 0
}
@ -669,8 +668,8 @@ func (r *Rewind) GotoCoords(coords coords.TelevisionCoords) error {
// if found index does not point to an immediately suitable state then try
// the adhocFrame state if available
if coords.Frame != r.entries[idx].TV.GetState(signal.ReqFramenum)+1 {
if r.adhocFrame != nil && r.adhocFrame.TV.GetState(signal.ReqFramenum) == coords.Frame-1 {
if coords.Frame != r.entries[idx].TV.GetCoords().Frame+1 {
if r.adhocFrame != nil && r.adhocFrame.TV.GetCoords().Frame == coords.Frame-1 {
return r.plumbState(r.adhocFrame, coords)
}
}

View file

@ -19,7 +19,6 @@ import (
"github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/hardware/television"
"github.com/jetsetilly/gopher2600/hardware/television/signal"
)
// TimelineCounts is returned by a TimelineCounter implementation. The value
@ -155,13 +154,13 @@ func (r *Rewind) GetTimeline() Timeline {
//
// this has a consequence when the first time the circular array wraps
// around for the first time (the number of available entries drops by one)
sf := r.entries[r.start].TV.GetState(signal.ReqFramenum)
sf := r.entries[r.start].TV.GetCoords().Frame
if r.entries[r.start].level != levelReset {
sf++
}
r.timeline.AvailableStart = sf
r.timeline.AvailableEnd = r.entries[e].TV.GetState(signal.ReqFramenum)
r.timeline.AvailableEnd = r.entries[e].TV.GetCoords().Frame
return r.timeline
}