mirror of
https://github.com/JetSetIlly/Gopher2600.git
synced 2025-04-02 11:02:17 -04:00
updated QUANTUM and STEP commands to accoodate new quantum control window changed to support the three quantum options improved/corrected the conditions under which the ONSTEP command is run disassembly.ExecutedEntry() updates existing entry
206 lines
5.7 KiB
Go
206 lines
5.7 KiB
Go
// 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 debugger
|
|
|
|
// support functions for the rewind package that require more knowledge of
|
|
// the debugger than would otherwise be available.
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/jetsetilly/gopher2600/debugger/govern"
|
|
"github.com/jetsetilly/gopher2600/gui"
|
|
"github.com/jetsetilly/gopher2600/hardware/television/coords"
|
|
"github.com/jetsetilly/gopher2600/logger"
|
|
"github.com/jetsetilly/gopher2600/notifications"
|
|
)
|
|
|
|
// RewindByAmount moves forwards or backwards by specified frames. Negative
|
|
// numbers indicate backwards
|
|
func (dbg *Debugger) RewindByAmount(amount int) bool {
|
|
switch dbg.Mode() {
|
|
case govern.ModePlay:
|
|
coords := dbg.vcs.TV.GetCoords()
|
|
tl := dbg.Rewind.GetTimeline()
|
|
|
|
if amount < 0 && coords.Frame-1 <= tl.AvailableStart {
|
|
dbg.setStateQuiet(govern.Paused, true)
|
|
err := dbg.gui.SetFeature(gui.ReqEmulationNotify, notifications.NotifyRewindAtStart)
|
|
if err != nil {
|
|
logger.Log("debugger", err.Error())
|
|
}
|
|
return false
|
|
}
|
|
|
|
if amount > 0 && coords.Frame+1 >= tl.AvailableEnd {
|
|
dbg.setStateQuiet(govern.Paused, true)
|
|
err := dbg.gui.SetFeature(gui.ReqEmulationNotify, notifications.NotifyRewindAtEnd)
|
|
if err != nil {
|
|
logger.Log("debugger", err.Error())
|
|
}
|
|
return false
|
|
}
|
|
|
|
dbg.setStateQuiet(govern.Rewinding, true)
|
|
dbg.Rewind.GotoFrame(coords.Frame + amount)
|
|
dbg.setStateQuiet(govern.Paused, true)
|
|
|
|
var err error
|
|
if amount < 0 {
|
|
err = dbg.gui.SetFeature(gui.ReqEmulationNotify, notifications.NotifyRewindBack)
|
|
} else {
|
|
err = dbg.gui.SetFeature(gui.ReqEmulationNotify, notifications.NotifyRewindFoward)
|
|
}
|
|
if err != nil {
|
|
logger.Log("debugger", err.Error())
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
panic(fmt.Sprintf("Rewind: unsupported mode (%v)", dbg.Mode()))
|
|
}
|
|
|
|
// RewindToFrame measure from the current frame.
|
|
func (dbg *Debugger) RewindToFrame(fn int, last bool) bool {
|
|
switch dbg.Mode() {
|
|
case govern.ModeDebugger:
|
|
if dbg.State() == govern.Rewinding {
|
|
return false
|
|
}
|
|
|
|
// the function to push to the debugger/emulation routine
|
|
doRewind := func() error {
|
|
// upate catchup context before starting rewind process
|
|
dbg.catchupContext = catchupRewindToFrame
|
|
|
|
if last {
|
|
err := dbg.Rewind.GotoLast()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
err := dbg.Rewind.GotoFrame(fn)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// how we push the doRewind() function depends on what kind of inputloop we
|
|
// are currently in
|
|
dbg.PushFunctionImmediate(func() {
|
|
// set state to govern.Rewinding as soon as possible (but
|
|
// remembering that we must do it in the debugger goroutine)
|
|
dbg.setState(govern.Rewinding)
|
|
dbg.unwindLoop(doRewind)
|
|
})
|
|
|
|
return true
|
|
}
|
|
|
|
panic(fmt.Sprintf("RewindToFrame: unsupported mode (%v)", dbg.Mode()))
|
|
}
|
|
|
|
// GotoCoords rewinds the emulation to the specified coordinates.
|
|
func (dbg *Debugger) GotoCoords(coords coords.TelevisionCoords) bool {
|
|
switch dbg.Mode() {
|
|
case govern.ModeDebugger:
|
|
if dbg.State() == govern.Rewinding {
|
|
return false
|
|
}
|
|
|
|
// the function to push to the debugger/emulation routine
|
|
doRewind := func() error {
|
|
// upate catchup context before starting rewind process
|
|
dbg.catchupContext = catchupGotoCoords
|
|
|
|
err := dbg.Rewind.GotoCoords(coords)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// how we push the doRewind() function depends on what kind of inputloop we
|
|
// are currently in
|
|
dbg.PushFunctionImmediate(func() {
|
|
// set state to govern.Rewinding as soon as possible (but
|
|
// remembering that we must do it in the debugger goroutine)
|
|
dbg.setState(govern.Rewinding)
|
|
dbg.unwindLoop(doRewind)
|
|
})
|
|
|
|
return true
|
|
}
|
|
|
|
panic(fmt.Sprintf("GotoCoords: unsupported mode (%v)", dbg.Mode()))
|
|
}
|
|
|
|
// RerunLastNFrames measured from the current frame.
|
|
func (dbg *Debugger) RerunLastNFrames(frames int) bool {
|
|
switch dbg.Mode() {
|
|
case govern.ModeDebugger:
|
|
if dbg.State() == govern.Rewinding {
|
|
return false
|
|
}
|
|
|
|
// the disadvantage of RerunLastNFrames() is that it will always land on a
|
|
// CPU instruction boundary (this is because we must unwind the existing
|
|
// input loop before calling the rewind function)
|
|
//
|
|
// if we're in between instruction boundaries therefore we need to push a
|
|
// GotoCoords() request. get the current coordinates now
|
|
correctCoords := !dbg.liveDisasmEntry.Result.Final
|
|
coords := dbg.vcs.TV.GetCoords()
|
|
|
|
// the function to push to the debugger/emulation routine
|
|
doRewind := func() error {
|
|
err := dbg.Rewind.RerunLastNFrames(frames)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if correctCoords {
|
|
err = dbg.Rewind.GotoCoords(coords)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// how we push the doRewind() function depends on what kind of inputloop we
|
|
// are currently in
|
|
dbg.PushFunctionImmediate(func() {
|
|
// upate catchup context before starting rewind process
|
|
dbg.catchupContext = catrupRerunLastNFrames
|
|
|
|
// set state to govern.Rewinding as soon as possible (but
|
|
// remembering that we must do it in the debugger goroutine)
|
|
dbg.setState(govern.Rewinding)
|
|
dbg.unwindLoop(doRewind)
|
|
})
|
|
|
|
return true
|
|
}
|
|
|
|
panic(fmt.Sprintf("RerunLastNFrames: unsupported mode (%v)", dbg.Mode()))
|
|
}
|