removed emulation package. moved types to debugger/govern package

the emulation package has been unecessary since the amalgamation of the
debugger and play modes. in order to allow switching between the two
modes it was necessary to remove the playmode package and to move all
playmode loops and other considerations into the debugger package. as a
result the abstraction offered by the emulation package is uncessary
This commit is contained in:
JetSetIlly 2022-08-27 22:14:58 +01:00
parent faddd7dfb9
commit 28ffedbf11
49 changed files with 384 additions and 485 deletions

View file

@ -24,7 +24,7 @@ import (
"github.com/jetsetilly/gopher2600/cartridgeloader" "github.com/jetsetilly/gopher2600/cartridgeloader"
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/hardware" "github.com/jetsetilly/gopher2600/hardware"
"github.com/jetsetilly/gopher2600/hardware/instance" "github.com/jetsetilly/gopher2600/hardware/instance"
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper" "github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper"
@ -207,14 +207,14 @@ func (cmp *Comparison) CreateFromLoader(cartload cartridgeloader.Loader) error {
return return
} }
err = cmp.VCS.Run(func() (emulation.State, error) { err = cmp.VCS.Run(func() (govern.State, error) {
select { select {
case <-cmp.emulationQuit: case <-cmp.emulationQuit:
return emulation.Ending, nil return govern.Ending, nil
default: default:
} }
return emulation.Running, nil return govern.Running, nil
}) })
if err != nil { if err != nil {
cmp.driver.quit <- err cmp.driver.quit <- err

View file

@ -27,12 +27,12 @@ import (
"github.com/jetsetilly/gopher2600/coprocessor/developer" "github.com/jetsetilly/gopher2600/coprocessor/developer"
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/debugger/dbgmem" "github.com/jetsetilly/gopher2600/debugger/dbgmem"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/debugger/script" "github.com/jetsetilly/gopher2600/debugger/script"
"github.com/jetsetilly/gopher2600/debugger/terminal" "github.com/jetsetilly/gopher2600/debugger/terminal"
"github.com/jetsetilly/gopher2600/debugger/terminal/commandline" "github.com/jetsetilly/gopher2600/debugger/terminal/commandline"
"github.com/jetsetilly/gopher2600/disassembly" "github.com/jetsetilly/gopher2600/disassembly"
"github.com/jetsetilly/gopher2600/disassembly/symbols" "github.com/jetsetilly/gopher2600/disassembly/symbols"
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/gui" "github.com/jetsetilly/gopher2600/gui"
"github.com/jetsetilly/gopher2600/hardware/cpu/registers" "github.com/jetsetilly/gopher2600/hardware/cpu/registers"
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/plusrom" "github.com/jetsetilly/gopher2600/hardware/memory/cartridge/plusrom"
@ -266,7 +266,7 @@ func (dbg *Debugger) processTokens(tokens *commandline.Tokens) error {
coords = dbg.vcs.TV.AdjCoords(adj, adjAmount) coords = dbg.vcs.TV.AdjCoords(adj, adjAmount)
} }
dbg.setState(emulation.Rewinding) dbg.setState(govern.Rewinding)
dbg.unwindLoop(func() error { dbg.unwindLoop(func() error {
// update catchupQuantum before starting rewind process // update catchupQuantum before starting rewind process
dbg.catchupQuantum = dbg.stepQuantum dbg.catchupQuantum = dbg.stepQuantum
@ -380,13 +380,13 @@ func (dbg *Debugger) processTokens(tokens *commandline.Tokens) error {
dbg.runUntilHalt = false dbg.runUntilHalt = false
if arg == "LAST" { if arg == "LAST" {
dbg.setState(emulation.Rewinding) dbg.setState(govern.Rewinding)
dbg.unwindLoop(dbg.Rewind.GotoLast) dbg.unwindLoop(dbg.Rewind.GotoLast)
} else if arg == "SUMMARY" { } else if arg == "SUMMARY" {
dbg.printLine(terminal.StyleInstrument, dbg.Rewind.String()) dbg.printLine(terminal.StyleInstrument, dbg.Rewind.String())
} else { } else {
frame, _ := strconv.Atoi(arg) frame, _ := strconv.Atoi(arg)
dbg.setState(emulation.Rewinding) dbg.setState(govern.Rewinding)
dbg.unwindLoop(func() error { dbg.unwindLoop(func() error {
err := dbg.Rewind.GotoFrame(frame) err := dbg.Rewind.GotoFrame(frame)
if err != nil { if err != nil {
@ -411,7 +411,7 @@ func (dbg *Debugger) processTokens(tokens *commandline.Tokens) error {
} }
} }
dbg.setState(emulation.Rewinding) dbg.setState(govern.Rewinding)
dbg.unwindLoop(func() error { dbg.unwindLoop(func() error {
err := dbg.Rewind.GotoCoords(coords) err := dbg.Rewind.GotoCoords(coords)
if err != nil { if err != nil {

View file

@ -30,11 +30,11 @@ import (
coprocDisasm "github.com/jetsetilly/gopher2600/coprocessor/disassembly" coprocDisasm "github.com/jetsetilly/gopher2600/coprocessor/disassembly"
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/debugger/dbgmem" "github.com/jetsetilly/gopher2600/debugger/dbgmem"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/debugger/script" "github.com/jetsetilly/gopher2600/debugger/script"
"github.com/jetsetilly/gopher2600/debugger/terminal" "github.com/jetsetilly/gopher2600/debugger/terminal"
"github.com/jetsetilly/gopher2600/debugger/terminal/commandline" "github.com/jetsetilly/gopher2600/debugger/terminal/commandline"
"github.com/jetsetilly/gopher2600/disassembly" "github.com/jetsetilly/gopher2600/disassembly"
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/gui" "github.com/jetsetilly/gopher2600/gui"
"github.com/jetsetilly/gopher2600/hardware" "github.com/jetsetilly/gopher2600/hardware"
"github.com/jetsetilly/gopher2600/hardware/cpu/execution" "github.com/jetsetilly/gopher2600/hardware/cpu/execution"
@ -290,7 +290,7 @@ type Debugger struct {
// CreateUserInterface is used to initialise the user interface used by the // CreateUserInterface is used to initialise the user interface used by the
// emulation. It returns an instance of both the GUI and Terminal interfaces // emulation. It returns an instance of both the GUI and Terminal interfaces
// in the repsective packages. // in the repsective packages.
type CreateUserInterface func(emulation.Emulation) (gui.GUI, terminal.Terminal, error) type CreateUserInterface func(*Debugger) (gui.GUI, terminal.Terminal, error)
// NewDebugger creates and initialises everything required for a new debugging // NewDebugger creates and initialises everything required for a new debugging
// session. // session.
@ -312,8 +312,8 @@ func NewDebugger(opts CommandLineOptions, create CreateUserInterface) (*Debugger
// emulator is starting in the "none" mode (the advangatge of this is that // emulator is starting in the "none" mode (the advangatge of this is that
// we get to set the underlying type of the atomic.Value early before // we get to set the underlying type of the atomic.Value early before
// anyone has a change to call State() or Mode() from another thread) // anyone has a change to call State() or Mode() from another thread)
dbg.state.Store(emulation.EmulatorStart) dbg.state.Store(govern.EmulatorStart)
dbg.mode.Store(emulation.ModeNone) dbg.mode.Store(govern.ModeNone)
var err error var err error
@ -449,17 +449,17 @@ func NewDebugger(opts CommandLineOptions, create CreateUserInterface) (*Debugger
} }
// VCS implements the emulation.Emulation interface. // VCS implements the emulation.Emulation interface.
func (dbg *Debugger) VCS() emulation.VCS { func (dbg *Debugger) VCS() *hardware.VCS {
return dbg.vcs return dbg.vcs
} }
// TV implements the emulation.Emulation interface. // TV implements the emulation.Emulation interface.
func (dbg *Debugger) TV() emulation.TV { func (dbg *Debugger) TV() *television.Television {
return dbg.vcs.TV return dbg.vcs.TV
} }
// Debugger implements the emulation.Emulation interface. // Debugger implements the emulation.Emulation interface.
func (dbg *Debugger) Debugger() emulation.Debugger { func (dbg *Debugger) Debugger() *Debugger {
return dbg return dbg
} }
@ -469,13 +469,13 @@ func (dbg *Debugger) UserInput() chan userinput.Event {
} }
// State implements the emulation.Emulation interface. // State implements the emulation.Emulation interface.
func (dbg *Debugger) State() emulation.State { func (dbg *Debugger) State() govern.State {
return dbg.state.Load().(emulation.State) return dbg.state.Load().(govern.State)
} }
// Mode implements the emulation.Emulation interface. // Mode implements the emulation.Emulation interface.
func (dbg *Debugger) Mode() emulation.Mode { func (dbg *Debugger) Mode() govern.Mode {
return dbg.mode.Load().(emulation.Mode) return dbg.mode.Load().(govern.Mode)
} }
// set the emulation state // set the emulation state
@ -484,7 +484,7 @@ func (dbg *Debugger) Mode() emulation.Mode {
// debugger.SetFeature(ReqSetPause) even from within the debugger package // debugger.SetFeature(ReqSetPause) even from within the debugger package
// (SetFeature() puts the request on the RawEvent Queue meaning it will be // (SetFeature() puts the request on the RawEvent Queue meaning it will be
// inserted in the input loop correctly) // inserted in the input loop correctly)
func (dbg *Debugger) setState(state emulation.State) { func (dbg *Debugger) setState(state govern.State) {
dbg.setStateQuiet(state, false) dbg.setStateQuiet(state, false)
} }
@ -493,8 +493,8 @@ func (dbg *Debugger) setState(state emulation.State) {
// //
// * see setState() comment, although debugger.SetFeature(ReqSetPause) will // * see setState() comment, although debugger.SetFeature(ReqSetPause) will
// always be "noisy" // always be "noisy"
func (dbg *Debugger) setStateQuiet(state emulation.State, quiet bool) { func (dbg *Debugger) setStateQuiet(state govern.State, quiet bool) {
if state == emulation.Rewinding { if state == govern.Rewinding {
dbg.vcs.Mem.Cart.BreakpointsDisable(true) dbg.vcs.Mem.Cart.BreakpointsDisable(true)
dbg.endPlayback() dbg.endPlayback()
dbg.endRecording() dbg.endRecording()
@ -533,15 +533,15 @@ func (dbg *Debugger) setStateQuiet(state emulation.State, quiet bool) {
prevState := dbg.State() prevState := dbg.State()
dbg.state.Store(state) dbg.state.Store(state)
if !quiet && dbg.Mode() == emulation.ModePlay { if !quiet && dbg.Mode() == govern.ModePlay {
switch state { switch state {
case emulation.Initialising: case govern.Initialising:
dbg.gui.SetFeature(gui.ReqEmulationEvent, emulation.EventInitialising) dbg.gui.SetFeature(gui.ReqEmulationEvent, govern.EventInitialising)
case emulation.Paused: case govern.Paused:
dbg.gui.SetFeature(gui.ReqEmulationEvent, emulation.EventPause) dbg.gui.SetFeature(gui.ReqEmulationEvent, govern.EventPause)
case emulation.Running: case govern.Running:
if prevState > emulation.Initialising { if prevState > govern.Initialising {
dbg.gui.SetFeature(gui.ReqEmulationEvent, emulation.EventRun) dbg.gui.SetFeature(gui.ReqEmulationEvent, govern.EventRun)
} }
} }
} }
@ -552,7 +552,7 @@ func (dbg *Debugger) setStateQuiet(state emulation.State, quiet bool) {
// * consider using debugger.SetFeature(ReqSetMode) even from within the // * consider using debugger.SetFeature(ReqSetMode) even from within the
// debugger package (SetFeature() puts the request on the RawEvent Queue // debugger package (SetFeature() puts the request on the RawEvent Queue
// meaning it will be inserted in the input loop correctly) // meaning it will be inserted in the input loop correctly)
func (dbg *Debugger) setMode(mode emulation.Mode) error { func (dbg *Debugger) setMode(mode govern.Mode) error {
if dbg.Mode() == mode { if dbg.Mode() == mode {
return nil return nil
} }
@ -566,8 +566,8 @@ func (dbg *Debugger) setMode(mode emulation.Mode) error {
// however, because the user has asked to switch to playmode we should // however, because the user has asked to switch to playmode we should
// cause the debugger mode to run until the halting condition is matched // cause the debugger mode to run until the halting condition is matched
// (which we know will occur in the almost immediate future) // (which we know will occur in the almost immediate future)
if mode == emulation.ModePlay && !dbg.halting.allowPlaymode() { if mode == govern.ModePlay && !dbg.halting.allowPlaymode() {
if dbg.Mode() == emulation.ModeDebugger { if dbg.Mode() == govern.ModeDebugger {
dbg.runUntilHalt = true dbg.runUntilHalt = true
dbg.continueEmulation = true dbg.continueEmulation = true
} }
@ -601,26 +601,26 @@ func (dbg *Debugger) setMode(mode emulation.Mode) error {
// screen.go) // screen.go)
switch dbg.Mode() { switch dbg.Mode() {
case emulation.ModePlay: case govern.ModePlay:
dbg.vcs.TV.AddFrameTrigger(dbg.Rewind) dbg.vcs.TV.AddFrameTrigger(dbg.Rewind)
dbg.vcs.TV.AddFrameTrigger(dbg.counter) dbg.vcs.TV.AddFrameTrigger(dbg.counter)
// simple detection of whether cartridge is ejected when switching to // simple detection of whether cartridge is ejected when switching to
// playmode. if it is ejected then open ROM selected. // playmode. if it is ejected then open ROM selected.
if dbg.Mode() == emulation.ModePlay && dbg.vcs.Mem.Cart.IsEjected() { if dbg.Mode() == govern.ModePlay && dbg.vcs.Mem.Cart.IsEjected() {
err = dbg.forceROMSelector() err = dbg.forceROMSelector()
if err != nil { if err != nil {
return curated.Errorf("debugger: %v", err) return curated.Errorf("debugger: %v", err)
} }
} else { } else {
dbg.setState(emulation.Running) dbg.setState(govern.Running)
} }
case emulation.ModeDebugger: case govern.ModeDebugger:
dbg.vcs.TV.AddFrameTrigger(dbg.Rewind) dbg.vcs.TV.AddFrameTrigger(dbg.Rewind)
dbg.vcs.TV.AddFrameTrigger(dbg.ref) dbg.vcs.TV.AddFrameTrigger(dbg.ref)
dbg.vcs.TV.AddFrameTrigger(dbg.counter) dbg.vcs.TV.AddFrameTrigger(dbg.counter)
dbg.setState(emulation.Paused) dbg.setState(govern.Paused)
// debugger needs knowledge about previous frames (via the reflector) // debugger needs knowledge about previous frames (via the reflector)
// if we're moving from playmode. also we want to make sure we end on // if we're moving from playmode. also we want to make sure we end on
@ -630,7 +630,7 @@ func (dbg *Debugger) setMode(mode emulation.Mode) error {
// catchupEndAdj we will always enter the debugger on the last cycle of // catchupEndAdj we will always enter the debugger on the last cycle of
// an instruction. although correct in terms of coordinates, is // an instruction. although correct in terms of coordinates, is
// confusing. // confusing.
if prevMode == emulation.ModePlay { if prevMode == govern.ModePlay {
dbg.catchupEndAdj = true dbg.catchupEndAdj = true
dbg.RerunLastNFrames(2) dbg.RerunLastNFrames(2)
} }
@ -692,7 +692,7 @@ func (dbg *Debugger) StartInDebugMode(filename string) error {
return curated.Errorf("debugger: %v", err) return curated.Errorf("debugger: %v", err)
} }
err = dbg.setMode(emulation.ModeDebugger) err = dbg.setMode(govern.ModeDebugger)
if err != nil { if err != nil {
return curated.Errorf("debugger: %v", err) return curated.Errorf("debugger: %v", err)
} }
@ -808,7 +808,7 @@ func (dbg *Debugger) StartInPlayMode(filename string) error {
return curated.Errorf("debugger: %v", err) return curated.Errorf("debugger: %v", err)
} }
err = dbg.setMode(emulation.ModePlay) err = dbg.setMode(govern.ModePlay)
if err != nil { if err != nil {
return curated.Errorf("debugger: %v", err) return curated.Errorf("debugger: %v", err)
} }
@ -842,7 +842,7 @@ func (dbg *Debugger) run() error {
// inputloop will continue until debugger is to be terminated // inputloop will continue until debugger is to be terminated
for dbg.running { for dbg.running {
switch dbg.Mode() { switch dbg.Mode() {
case emulation.ModePlay: case govern.ModePlay:
err := dbg.playLoop() err := dbg.playLoop()
if err != nil { if err != nil {
// if we ever encounter a cartridge ejected error in playmode // if we ever encounter a cartridge ejected error in playmode
@ -856,14 +856,14 @@ func (dbg *Debugger) run() error {
return curated.Errorf("debugger: %v", err) return curated.Errorf("debugger: %v", err)
} }
} }
case emulation.ModeDebugger: case govern.ModeDebugger:
switch dbg.State() { switch dbg.State() {
case emulation.Running: case govern.Running:
dbg.runUntilHalt = true dbg.runUntilHalt = true
dbg.continueEmulation = true dbg.continueEmulation = true
case emulation.Paused: case govern.Paused:
dbg.haltImmediately = true dbg.haltImmediately = true
case emulation.Rewinding: case govern.Rewinding:
default: default:
return curated.Errorf("emulation state not supported on *start* of debugging loop: %s", dbg.State()) return curated.Errorf("emulation state not supported on *start* of debugging loop: %s", dbg.State())
} }
@ -880,7 +880,7 @@ func (dbg *Debugger) run() error {
return curated.Errorf("debugger: %v", err) return curated.Errorf("debugger: %v", err)
} }
dbg.unwindLoopRestart = nil dbg.unwindLoopRestart = nil
} else if dbg.State() == emulation.Ending { } else if dbg.State() == govern.Ending {
dbg.running = false dbg.running = false
} }
default: default:
@ -948,19 +948,19 @@ func (dbg *Debugger) attachCartridge(cartload cartridgeloader.Loader) (e error)
dbg.bots.Quit() dbg.bots.Quit()
// attching a cartridge implies the initialise state // attching a cartridge implies the initialise state
dbg.setState(emulation.Initialising) dbg.setState(govern.Initialising)
// set state after initialisation according to the emulation mode // set state after initialisation according to the emulation mode
defer func() { defer func() {
switch dbg.Mode() { switch dbg.Mode() {
case emulation.ModeDebugger: case govern.ModeDebugger:
if dbg.runUntilHalt && e == nil { if dbg.runUntilHalt && e == nil {
dbg.setState(emulation.Running) dbg.setState(govern.Running)
} else { } else {
dbg.setState(emulation.Paused) dbg.setState(govern.Paused)
} }
case emulation.ModePlay: case govern.ModePlay:
dbg.setState(emulation.Running) dbg.setState(govern.Running)
} }
}() }()
@ -1224,12 +1224,12 @@ func (dbg *Debugger) endComparison() {
func (dbg *Debugger) hotload() (e error) { func (dbg *Debugger) hotload() (e error) {
// tell GUI that we're in the initialistion phase // tell GUI that we're in the initialistion phase
dbg.setState(emulation.Initialising) dbg.setState(govern.Initialising)
defer func() { defer func() {
if dbg.runUntilHalt && e == nil { if dbg.runUntilHalt && e == nil {
dbg.setState(emulation.Running) dbg.setState(govern.Running)
} else { } else {
dbg.gui.SetFeature(gui.ReqEmulationEvent, emulation.EventPause) dbg.gui.SetFeature(gui.ReqEmulationEvent, govern.EventPause)
} }
}() }()

View file

@ -22,7 +22,6 @@ import (
"github.com/jetsetilly/gopher2600/debugger" "github.com/jetsetilly/gopher2600/debugger"
"github.com/jetsetilly/gopher2600/debugger/terminal" "github.com/jetsetilly/gopher2600/debugger/terminal"
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/gui" "github.com/jetsetilly/gopher2600/gui"
"github.com/jetsetilly/gopher2600/prefs" "github.com/jetsetilly/gopher2600/prefs"
) )
@ -143,7 +142,7 @@ func TestDebugger_withNonExistantInitScript(t *testing.T) {
var trm *mockTerm var trm *mockTerm
create := func(e emulation.Emulation) (gui.GUI, terminal.Terminal, error) { create := func(dbg *debugger.Debugger) (gui.GUI, terminal.Terminal, error) {
trm = newMockTerm(t) trm = newMockTerm(t)
return &mockGUI{}, trm, nil return &mockGUI{}, trm, nil
} }
@ -166,7 +165,7 @@ func TestDebugger(t *testing.T) {
var trm *mockTerm var trm *mockTerm
create := func(e emulation.Emulation) (gui.GUI, terminal.Terminal, error) { create := func(dbg *debugger.Debugger) (gui.GUI, terminal.Terminal, error) {
trm = newMockTerm(t) trm = newMockTerm(t)
return &mockGUI{}, trm, nil return &mockGUI{}, trm, nil
} }

View file

@ -19,7 +19,7 @@ import (
"fmt" "fmt"
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/hardware/cpu/instructions" "github.com/jetsetilly/gopher2600/hardware/cpu/instructions"
"github.com/jetsetilly/gopher2600/hardware/cpu/registers" "github.com/jetsetilly/gopher2600/hardware/cpu/registers"
"github.com/jetsetilly/gopher2600/hardware/memory" "github.com/jetsetilly/gopher2600/hardware/memory"
@ -48,7 +48,7 @@ func (dbg *Debugger) PushDeepPoke(addr uint16, value uint8, newValue uint8, valu
} }
dbg.PushRawEventImmediate(func() { dbg.PushRawEventImmediate(func() {
dbg.setStateQuiet(emulation.Rewinding, true) dbg.setStateQuiet(govern.Rewinding, true)
dbg.unwindLoop(doDeepPoke) dbg.unwindLoop(doDeepPoke)
}) })

View file

@ -13,14 +13,11 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Gopher2600. If not, see <https://www.gnu.org/licenses/>. // along with Gopher2600. If not, see <https://www.gnu.org/licenses/>.
// Package emulation is an abstraction of the various modes Gopher2600 can // Package govern defines the types that define the current condition of the
// operate in, principally play-mode and the debugger. // emulation. The three conditions are Mode, State and Event.
// //
// It is useful when linking packages/types that require a *passive* knowledge // Also defined is the method of requesting a state change from the GUI. Most
// of the emulation. For example, a GUI might want to know what the current // often state change comes from the emulation but in some intances it is
// state of the emulation is. // necessary to instruct the emulation to change mode or state - for example,
// // from the GUI as a result of the a user request.
// Some package types might still need an active knowledge of the emulation package govern
// however. In which case, simply relying on the Emulation interface is
// probably not enough.
package emulation

View file

@ -13,54 +13,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Gopher2600. If not, see <https://www.gnu.org/licenses/>. // along with Gopher2600. If not, see <https://www.gnu.org/licenses/>.
package emulation package govern
import ( // Mode inidicates the broad features of the emulation. Currently defined to be
"github.com/jetsetilly/gopher2600/userinput" // debugger and play.
)
// TV is a minimal abstraction of the TV hardware. Exists mainly to avoid a
// circular import to the hardware package.
//
// The only likely implementation of this interface is the
// television.Television type.
type TV interface {
}
// VCS is a minimal abstraction of the VCS hardware. Exists mainly to avoid a
// circular import to the hardware package.
//
// The only likely implementation of this interface is the hardware.VCS type.
type VCS interface {
}
// VCS is a minimal abstraction of the Gopher2600 debugger. Exists mainly to
// avoid a circular import to the debugger package.
//
// The only likely implementation of this interface is the debugger.Debugger
// type.
type Debugger interface {
}
// Emulation defines the public functions required for a GUI implementation
// (and possibly other things) to interface with the underlying emulator.
type Emulation interface {
TV() TV
VCS() VCS
Debugger() Debugger
UserInput() chan userinput.Event
// Send a request to set an emulation feature
SetFeature(request FeatureReq, args ...FeatureReqData) error
// Immediate request for the state and mode of the emulation
State() State
Mode() Mode
}
// Mode inidicates the broad features of the emulation. For example, Debugger
// indicates that the emulation is capable or is willing to handle debugging
// features.
type Mode int type Mode int
func (m Mode) String() string { func (m Mode) String() string {
@ -112,9 +68,9 @@ const (
Ending Ending
) )
// Event describes an event that might occur in the emulation which is outside // Event is something that happens to change the state of the emulation. For
// of the scope of the VCS. For example, when the emulation is paused an // example, the user presses the pause while playing game. This will cause the
// EventPause can be sent to the GUI (see FeatureReq type in the gui package). // GUI to send an EventPause event to the emulation.
type Event int type Event int
// List of defined events. // List of defined events.
@ -130,3 +86,30 @@ const (
EventMute EventMute
EventUnmute EventUnmute
) )
// FeatureReq is used to request the setting of an emulation attribute
// eg. a pause request from the GUI
type FeatureReq string
// FeatureReqData represents the information associated with a FeatureReq. See
// commentary for the defined FeatureReq values for the underlying type.
type FeatureReqData interface{}
// List of valid feature requests. argument must be of the type specified or
// else the interface{} type conversion will fail and the application will
// probably crash.
//
// Note that, like the name suggests, these are requests, they may or may not
// be satisfied depending on other conditions in the GUI.
const (
// notify gui of the underlying emulation mode.
ReqSetPause FeatureReq = "ReqSetPause" // bool
// change emulation mode
ReqSetMode FeatureReq = "ReqSetMode" // emulation.Mode
)
// Sentinal error returned if emulation does no support requested feature.
const (
UnsupportedEmulationFeature = "unsupported emulation feature: %v"
)

View file

@ -16,7 +16,7 @@
package debugger package debugger
import ( import (
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/hardware/television/coords" "github.com/jetsetilly/gopher2600/hardware/television/coords"
) )
@ -26,25 +26,25 @@ import (
// required for catchupLoop(). // required for catchupLoop().
func (dbg *Debugger) CatchUpLoop(tgt coords.TelevisionCoords) error { func (dbg *Debugger) CatchUpLoop(tgt coords.TelevisionCoords) error {
switch dbg.Mode() { switch dbg.Mode() {
case emulation.ModePlay: case govern.ModePlay:
fpscap := dbg.vcs.TV.SetFPSCap(false) fpscap := dbg.vcs.TV.SetFPSCap(false)
defer dbg.vcs.TV.SetFPSCap(fpscap) defer dbg.vcs.TV.SetFPSCap(fpscap)
dbg.vcs.Run(func() (emulation.State, error) { dbg.vcs.Run(func() (govern.State, error) {
dbg.userInputHandler_catchUpLoop() dbg.userInputHandler_catchUpLoop()
coords := dbg.vcs.TV.GetCoords() coords := dbg.vcs.TV.GetCoords()
if coords.Frame >= tgt.Frame { if coords.Frame >= tgt.Frame {
return emulation.Ending, nil return govern.Ending, nil
} }
return emulation.Running, nil return govern.Running, nil
}) })
case emulation.ModeDebugger: case govern.ModeDebugger:
// turn off TV's fps frame limiter // turn off TV's fps frame limiter
fpsCap := dbg.vcs.TV.SetFPSCap(false) fpsCap := dbg.vcs.TV.SetFPSCap(false)
// we've already set emulation state to emulation.Rewinding // we've already set emulation state to govern.Rewinding
dbg.catchupContinue = func() bool { dbg.catchupContinue = func() bool {
newCoords := dbg.vcs.TV.GetCoords() newCoords := dbg.vcs.TV.GetCoords()
@ -69,7 +69,7 @@ func (dbg *Debugger) CatchUpLoop(tgt coords.TelevisionCoords) error {
dbg.vcs.TV.SetFPSCap(fpsCap) dbg.vcs.TV.SetFPSCap(fpsCap)
dbg.catchupContinue = nil dbg.catchupContinue = nil
dbg.catchupEnd = nil dbg.catchupEnd = nil
dbg.setState(emulation.Paused) dbg.setState(govern.Paused)
dbg.runUntilHalt = false dbg.runUntilHalt = false
dbg.continueEmulation = dbg.catchupEndAdj dbg.continueEmulation = dbg.catchupEndAdj
dbg.catchupEndAdj = false dbg.catchupEndAdj = false

View file

@ -19,9 +19,9 @@ import (
"io" "io"
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/debugger/script" "github.com/jetsetilly/gopher2600/debugger/script"
"github.com/jetsetilly/gopher2600/debugger/terminal" "github.com/jetsetilly/gopher2600/debugger/terminal"
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/hardware/cpu" "github.com/jetsetilly/gopher2600/hardware/cpu"
"github.com/jetsetilly/gopher2600/logger" "github.com/jetsetilly/gopher2600/logger"
) )
@ -35,7 +35,7 @@ import (
// function is being called. // function is being called.
// //
// note that the debugger state is not changed by this function. it is up to // note that the debugger state is not changed by this function. it is up to
// the caller of the function to set emulation.State appropriately. // the caller of the function to set govern.State appropriately.
func (dbg *Debugger) unwindLoop(onRestart func() error) { func (dbg *Debugger) unwindLoop(onRestart func() error) {
dbg.unwindLoopRestart = onRestart dbg.unwindLoopRestart = onRestart
} }
@ -65,7 +65,7 @@ func (dbg *Debugger) catchupLoop(inputter terminal.Input) error {
if !dbg.vcs.CPU.LastResult.Final { if !dbg.vcs.CPU.LastResult.Final {
// if we're in the rewinding state then a new rewind event has // if we're in the rewinding state then a new rewind event has
// started and we must return immediately so that it can continue // started and we must return immediately so that it can continue
if dbg.State() == emulation.Rewinding { if dbg.State() == govern.Rewinding {
return nil return nil
} }
@ -140,7 +140,7 @@ func (dbg *Debugger) inputLoop(inputter terminal.Input, isVideoStep bool) error
var err error var err error
for dbg.running { for dbg.running {
if dbg.Mode() != emulation.ModeDebugger { if dbg.Mode() != govern.ModeDebugger {
return nil return nil
} }
@ -186,7 +186,7 @@ func (dbg *Debugger) inputLoop(inputter terminal.Input, isVideoStep bool) error
} }
// emulation has been put into a different mode. exit loop immediately // emulation has been put into a different mode. exit loop immediately
if dbg.Mode() != emulation.ModeDebugger { if dbg.Mode() != govern.ModeDebugger {
return nil return nil
} }
@ -278,7 +278,7 @@ func (dbg *Debugger) inputLoop(inputter terminal.Input, isVideoStep bool) error
} }
// set pause emulation state // set pause emulation state
dbg.setState(emulation.Paused) dbg.setState(govern.Paused)
// take note of current machine state if the emulation was in a running // take note of current machine state if the emulation was in a running
// state and is halting just now // state and is halting just now
@ -324,7 +324,7 @@ func (dbg *Debugger) inputLoop(inputter terminal.Input, isVideoStep bool) error
} }
// emulation has been put into a different mode. exit loop immediately // emulation has been put into a different mode. exit loop immediately
if dbg.Mode() != emulation.ModeDebugger { if dbg.Mode() != govern.ModeDebugger {
return nil return nil
} }
@ -351,10 +351,10 @@ func (dbg *Debugger) inputLoop(inputter terminal.Input, isVideoStep bool) error
// stepping. // stepping.
if dbg.halting.volatileTraps.isEmpty() { if dbg.halting.volatileTraps.isEmpty() {
if inputter.IsInteractive() { if inputter.IsInteractive() {
dbg.setState(emulation.Running) dbg.setState(govern.Running)
} }
} else { } else {
dbg.setState(emulation.Stepping) dbg.setState(govern.Stepping)
} }
// update comparison point before execution continues // update comparison point before execution continues
@ -362,7 +362,7 @@ func (dbg *Debugger) inputLoop(inputter terminal.Input, isVideoStep bool) error
dbg.Rewind.SetComparison() dbg.Rewind.SetComparison()
} }
} else if inputter.IsInteractive() { } else if inputter.IsInteractive() {
dbg.setState(emulation.Stepping) dbg.setState(govern.Stepping)
} }
} }

View file

@ -17,8 +17,8 @@ package debugger
import ( import (
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/debugger/terminal" "github.com/jetsetilly/gopher2600/debugger/terminal"
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/gui" "github.com/jetsetilly/gopher2600/gui"
"github.com/jetsetilly/gopher2600/hardware" "github.com/jetsetilly/gopher2600/hardware"
"github.com/jetsetilly/gopher2600/userinput" "github.com/jetsetilly/gopher2600/userinput"
@ -65,7 +65,7 @@ func (dbg *Debugger) playLoop() error {
dbg.liveBankInfo = dbg.vcs.Mem.Cart.GetBank(dbg.vcs.CPU.PC.Address()) dbg.liveBankInfo = dbg.vcs.Mem.Cart.GetBank(dbg.vcs.CPU.PC.Address())
// run and handle events // run and handle events
return dbg.vcs.Run(func() (emulation.State, error) { return dbg.vcs.Run(func() (govern.State, error) {
// update counters. because of the way LastResult works we need to make // update counters. because of the way LastResult works we need to make
// sure we only use it in the event that the CPU RdyFlag is set // sure we only use it in the event that the CPU RdyFlag is set
// //
@ -93,12 +93,12 @@ func (dbg *Debugger) playLoop() error {
if dbg.halting.halt { if dbg.halting.halt {
// set debugging mode. halting messages will be preserved and // set debugging mode. halting messages will be preserved and
// shown when entering debugging mode // shown when entering debugging mode
dbg.setMode(emulation.ModeDebugger) dbg.setMode(govern.ModeDebugger)
return emulation.Ending, nil return govern.Ending, nil
} }
if dbg.Mode() != emulation.ModePlay { if dbg.Mode() != govern.ModePlay {
return emulation.Ending, nil return govern.Ending, nil
} }
// return without checking interface unless we exceed the // return without checking interface unless we exceed the
@ -113,12 +113,12 @@ func (dbg *Debugger) playLoop() error {
case <-dbg.eventCheckPulse.C: case <-dbg.eventCheckPulse.C:
err := dbg.readEventsHandler() err := dbg.readEventsHandler()
if err != nil { if err != nil {
return emulation.Ending, err return govern.Ending, err
} }
default: default:
} }
if dbg.state.Load().(emulation.State) == emulation.Running { if dbg.state.Load().(govern.State) == govern.Running {
dbg.Rewind.RecordState() dbg.Rewind.RecordState()
} }

View file

@ -17,50 +17,49 @@ package debugger
import ( import (
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/logger" "github.com/jetsetilly/gopher2600/logger"
) )
func argLen(args []emulation.FeatureReqData, expectedLen int) error { func argLen(args []govern.FeatureReqData, expectedLen int) error {
if len(args) != expectedLen { if len(args) != expectedLen {
return curated.Errorf("wrong number of arguments (%d instead of %d)", len(args), expectedLen) return curated.Errorf("wrong number of arguments (%d instead of %d)", len(args), expectedLen)
} }
return nil return nil
} }
// ReqFeature implements the emulation.Emulation interface. // ReqFeature implements the govern.Emulation interface.
func (dbg *Debugger) SetFeature(request emulation.FeatureReq, args ...emulation.FeatureReqData) error { func (dbg *Debugger) SetFeature(request govern.FeatureReq, args ...govern.FeatureReqData) error {
var err error var err error
switch request { switch request {
case emulation.ReqSetPause: case govern.ReqSetPause:
err = argLen(args, 1) err = argLen(args, 1)
if err != nil { if err != nil {
return curated.Errorf("debugger: %v", err) return curated.Errorf("debugger: %v", err)
} }
switch dbg.Mode() { switch dbg.Mode() {
case emulation.ModePlay: case govern.ModePlay:
dbg.PushRawEvent(func() { dbg.PushRawEvent(func() {
// Pause implements the emulation.Emulation interface.
if args[0].(bool) { if args[0].(bool) {
dbg.setState(emulation.Paused) dbg.setState(govern.Paused)
} else { } else {
dbg.setState(emulation.Running) dbg.setState(govern.Running)
} }
}) })
case emulation.ModeDebugger: case govern.ModeDebugger:
err = curated.Errorf("not reacting to %s in debug mode (use terminal input instead)", request) err = curated.Errorf("not reacting to %s in debug mode (use terminal input instead)", request)
} }
case emulation.ReqSetMode: case govern.ReqSetMode:
err = argLen(args, 1) err = argLen(args, 1)
if err != nil { if err != nil {
return curated.Errorf("debugger: %v", err) return curated.Errorf("debugger: %v", err)
} }
dbg.PushRawEventImmediate(func() { dbg.PushRawEventImmediate(func() {
err := dbg.setMode(args[0].(emulation.Mode)) err := dbg.setMode(args[0].(govern.Mode))
if err != nil { if err != nil {
logger.Logf("debugger", err.Error()) logger.Logf("debugger", err.Error())
} }

View file

@ -22,7 +22,7 @@ import (
"fmt" "fmt"
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/gui" "github.com/jetsetilly/gopher2600/gui"
"github.com/jetsetilly/gopher2600/hardware/television/coords" "github.com/jetsetilly/gopher2600/hardware/television/coords"
) )
@ -34,30 +34,30 @@ func (dbg *Debugger) RewindByAmount(amount int) bool {
default: default:
panic(fmt.Sprintf("Rewind: unsupported mode (%v)", dbg.Mode())) panic(fmt.Sprintf("Rewind: unsupported mode (%v)", dbg.Mode()))
case emulation.ModePlay: case govern.ModePlay:
coords := dbg.vcs.TV.GetCoords() coords := dbg.vcs.TV.GetCoords()
tl := dbg.Rewind.GetTimeline() tl := dbg.Rewind.GetTimeline()
if amount < 0 && coords.Frame-1 <= tl.AvailableStart { if amount < 0 && coords.Frame-1 <= tl.AvailableStart {
dbg.setStateQuiet(emulation.Paused, true) dbg.setStateQuiet(govern.Paused, true)
dbg.gui.SetFeature(gui.ReqEmulationEvent, emulation.EventRewindAtStart) dbg.gui.SetFeature(gui.ReqEmulationEvent, govern.EventRewindAtStart)
return false return false
} }
if amount > 0 && coords.Frame+1 >= tl.AvailableEnd { if amount > 0 && coords.Frame+1 >= tl.AvailableEnd {
dbg.setStateQuiet(emulation.Paused, true) dbg.setStateQuiet(govern.Paused, true)
dbg.gui.SetFeature(gui.ReqEmulationEvent, emulation.EventRewindAtEnd) dbg.gui.SetFeature(gui.ReqEmulationEvent, govern.EventRewindAtEnd)
return false return false
} }
dbg.setStateQuiet(emulation.Rewinding, true) dbg.setStateQuiet(govern.Rewinding, true)
dbg.Rewind.GotoFrame(coords.Frame + amount) dbg.Rewind.GotoFrame(coords.Frame + amount)
dbg.setStateQuiet(emulation.Paused, true) dbg.setStateQuiet(govern.Paused, true)
if amount < 0 { if amount < 0 {
dbg.gui.SetFeature(gui.ReqEmulationEvent, emulation.EventRewindBack) dbg.gui.SetFeature(gui.ReqEmulationEvent, govern.EventRewindBack)
} else { } else {
dbg.gui.SetFeature(gui.ReqEmulationEvent, emulation.EventRewindFoward) dbg.gui.SetFeature(gui.ReqEmulationEvent, govern.EventRewindFoward)
} }
return true return true
@ -72,8 +72,8 @@ func (dbg *Debugger) RewindToFrame(fn int, last bool) bool {
default: default:
panic(fmt.Sprintf("RewindToFrame: unsupported mode (%v)", dbg.Mode())) panic(fmt.Sprintf("RewindToFrame: unsupported mode (%v)", dbg.Mode()))
case emulation.ModeDebugger: case govern.ModeDebugger:
if dbg.State() == emulation.Rewinding { if dbg.State() == govern.Rewinding {
return false return false
} }
@ -100,9 +100,9 @@ func (dbg *Debugger) RewindToFrame(fn int, last bool) bool {
// how we push the doRewind() function depends on what kind of inputloop we // how we push the doRewind() function depends on what kind of inputloop we
// are currently in // are currently in
dbg.PushRawEventImmediate(func() { dbg.PushRawEventImmediate(func() {
// set state to emulation.Rewinding as soon as possible (but // set state to govern.Rewinding as soon as possible (but
// remembering that we must do it in the debugger goroutine) // remembering that we must do it in the debugger goroutine)
dbg.setState(emulation.Rewinding) dbg.setState(govern.Rewinding)
dbg.unwindLoop(doRewind) dbg.unwindLoop(doRewind)
}) })
@ -118,8 +118,8 @@ func (dbg *Debugger) GotoCoords(coords coords.TelevisionCoords) bool {
default: default:
panic(fmt.Sprintf("GotoCoords: unsupported mode (%v)", dbg.Mode())) panic(fmt.Sprintf("GotoCoords: unsupported mode (%v)", dbg.Mode()))
case emulation.ModeDebugger: case govern.ModeDebugger:
if dbg.State() == emulation.Rewinding { if dbg.State() == govern.Rewinding {
return false return false
} }
@ -139,9 +139,9 @@ func (dbg *Debugger) GotoCoords(coords coords.TelevisionCoords) bool {
// how we push the doRewind() function depends on what kind of inputloop we // how we push the doRewind() function depends on what kind of inputloop we
// are currently in // are currently in
dbg.PushRawEventImmediate(func() { dbg.PushRawEventImmediate(func() {
// set state to emulation.Rewinding as soon as possible (but // set state to govern.Rewinding as soon as possible (but
// remembering that we must do it in the debugger goroutine) // remembering that we must do it in the debugger goroutine)
dbg.setState(emulation.Rewinding) dbg.setState(govern.Rewinding)
dbg.unwindLoop(doRewind) dbg.unwindLoop(doRewind)
}) })
@ -157,8 +157,8 @@ func (dbg *Debugger) RerunLastNFrames(frames int) bool {
default: default:
panic(fmt.Sprintf("RerunLastNFrames: unsupported mode (%v)", dbg.Mode())) panic(fmt.Sprintf("RerunLastNFrames: unsupported mode (%v)", dbg.Mode()))
case emulation.ModeDebugger: case govern.ModeDebugger:
if dbg.State() == emulation.Rewinding { if dbg.State() == govern.Rewinding {
return false return false
} }
@ -194,9 +194,9 @@ func (dbg *Debugger) RerunLastNFrames(frames int) bool {
// upate catchupQuantum before starting rewind process // upate catchupQuantum before starting rewind process
dbg.catchupQuantum = QuantumClock dbg.catchupQuantum = QuantumClock
// set state to emulation.Rewinding as soon as possible (but // set state to govern.Rewinding as soon as possible (but
// remembering that we must do it in the debugger goroutine) // remembering that we must do it in the debugger goroutine)
dbg.setState(emulation.Rewinding) dbg.setState(govern.Rewinding)
dbg.unwindLoop(doRewind) dbg.unwindLoop(doRewind)
}) })

View file

@ -17,8 +17,8 @@ package debugger
import ( import (
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/debugger/terminal" "github.com/jetsetilly/gopher2600/debugger/terminal"
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/userinput" "github.com/jetsetilly/gopher2600/userinput"
) )
@ -45,7 +45,7 @@ func (dbg *Debugger) userInputHandler(ev userinput.Event) error {
// mode specific special input (not passed to the VCS as controller input) // mode specific special input (not passed to the VCS as controller input)
switch dbg.Mode() { switch dbg.Mode() {
case emulation.ModePlay: case govern.ModePlay:
switch ev := ev.(type) { switch ev := ev.(type) {
case userinput.EventMouseWheel: case userinput.EventMouseWheel:
amount := int(ev.Delta) + dbg.rewindMouseWheelAccumulation amount := int(ev.Delta) + dbg.rewindMouseWheelAccumulation
@ -73,7 +73,7 @@ func (dbg *Debugger) userInputHandler(ev userinput.Event) error {
} }
} else { } else {
dbg.rewindKeyboardAccumulation = 0 dbg.rewindKeyboardAccumulation = 0
if dbg.State() != emulation.Running { if dbg.State() != govern.Running {
return nil return nil
} }
} }
@ -93,7 +93,7 @@ func (dbg *Debugger) userInputHandler(ev userinput.Event) error {
} }
} else { } else {
dbg.rewindKeyboardAccumulation = 0 dbg.rewindKeyboardAccumulation = 0
if dbg.State() != emulation.Running { if dbg.State() != govern.Running {
return nil return nil
} }
} }
@ -106,18 +106,18 @@ func (dbg *Debugger) userInputHandler(ev userinput.Event) error {
if ev.Down { if ev.Down {
switch ev.Button { switch ev.Button {
case userinput.GamepadButtonBack: case userinput.GamepadButtonBack:
if dbg.State() != emulation.Paused { if dbg.State() != govern.Paused {
dbg.SetFeature(emulation.ReqSetPause, true) dbg.SetFeature(govern.ReqSetPause, true)
} else { } else {
dbg.SetFeature(emulation.ReqSetPause, false) dbg.SetFeature(govern.ReqSetPause, false)
} }
return nil return nil
case userinput.GamepadButtonGuide: case userinput.GamepadButtonGuide:
switch dbg.Mode() { switch dbg.Mode() {
case emulation.ModePlay: case govern.ModePlay:
dbg.SetFeature(emulation.ReqSetMode, emulation.ModeDebugger) dbg.SetFeature(govern.ReqSetMode, govern.ModeDebugger)
case emulation.ModeDebugger: case govern.ModeDebugger:
dbg.SetFeature(emulation.ReqSetMode, emulation.ModePlay) dbg.SetFeature(govern.ReqSetMode, govern.ModePlay)
} }
} }
} }
@ -133,8 +133,8 @@ func (dbg *Debugger) userInputHandler(ev userinput.Event) error {
// direction). unpause if the emulation is currently paused // direction). unpause if the emulation is currently paused
// //
// * we're only allowing this for playmode // * we're only allowing this for playmode
if dbg.Mode() == emulation.ModePlay && dbg.State() == emulation.Paused && handled { if dbg.Mode() == govern.ModePlay && dbg.State() == govern.Paused && handled {
dbg.SetFeature(emulation.ReqSetPause, false) dbg.SetFeature(govern.ReqSetPause, false)
} }
return nil return nil

View file

@ -1,43 +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 emulation
// FeatureReq is used to request the setting of an emulation attribute
// eg. a pause request from the GUI
type FeatureReq string
// FeatureReqData represents the information associated with a FeatureReq. See
// commentary for the defined FeatureReq values for the underlying type.
type FeatureReqData interface{}
// List of valid feature requests. argument must be of the type specified or
// else the interface{} type conversion will fail and the application will
// probably crash.
//
// Note that, like the name suggests, these are requests, they may or may not
// be satisfied depending on other conditions in the GUI.
const (
// notify gui of the underlying emulation mode.
ReqSetPause FeatureReq = "ReqSetPause" // bool
// change emulation mode
ReqSetMode FeatureReq = "ReqSetMode" // emulation.Mode
)
// Sentinal error returned if emulation does no support requested feature.
const (
UnsupportedEmulationFeature = "unsupported emulation feature: %v"
)

View file

@ -27,11 +27,11 @@ import (
"github.com/jetsetilly/gopher2600/cartridgeloader" "github.com/jetsetilly/gopher2600/cartridgeloader"
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/debugger" "github.com/jetsetilly/gopher2600/debugger"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/debugger/terminal" "github.com/jetsetilly/gopher2600/debugger/terminal"
"github.com/jetsetilly/gopher2600/debugger/terminal/colorterm" "github.com/jetsetilly/gopher2600/debugger/terminal/colorterm"
"github.com/jetsetilly/gopher2600/debugger/terminal/plainterm" "github.com/jetsetilly/gopher2600/debugger/terminal/plainterm"
"github.com/jetsetilly/gopher2600/disassembly" "github.com/jetsetilly/gopher2600/disassembly"
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/gui" "github.com/jetsetilly/gopher2600/gui"
"github.com/jetsetilly/gopher2600/gui/sdlimgui" "github.com/jetsetilly/gopher2600/gui/sdlimgui"
"github.com/jetsetilly/gopher2600/hardware/riot/ports" "github.com/jetsetilly/gopher2600/hardware/riot/ports"
@ -236,10 +236,10 @@ func launch(sync *mainSync) {
fallthrough fallthrough
case "PLAY": case "PLAY":
err = emulate(emulation.ModePlay, md, sync) err = emulate(govern.ModePlay, md, sync)
case "DEBUG": case "DEBUG":
err = emulate(emulation.ModeDebugger, md, sync) err = emulate(govern.ModeDebugger, md, sync)
case "DISASM": case "DISASM":
err = disasm(md) err = disasm(md)
@ -267,7 +267,7 @@ const defaultInitScript = "debuggerInit"
// emulate is the main emulation launch function, shared by play and debug // emulate is the main emulation launch function, shared by play and debug
// modes. the other modes initialise and run the emulation differently. // modes. the other modes initialise and run the emulation differently.
func emulate(emulationMode emulation.Mode, md *modalflag.Modes, sync *mainSync) error { func emulate(emulationMode govern.Mode, md *modalflag.Modes, sync *mainSync) error {
// start new commandline mode. to this we'll add the command line arguments // start new commandline mode. to this we'll add the command line arguments
// that are specific to the emulation mode (it's unfortunate that mode is // that are specific to the emulation mode (it's unfortunate that mode is
// used to describe two separate concepts but they really have nothing to // used to describe two separate concepts but they really have nothing to
@ -297,7 +297,7 @@ func emulate(emulationMode emulation.Mode, md *modalflag.Modes, sync *mainSync)
opts.Profile = md.AddString("profile", "none", "run performance check with profiling: command separated CPU, MEM, TRACE or ALL") opts.Profile = md.AddString("profile", "none", "run performance check with profiling: command separated CPU, MEM, TRACE or ALL")
// playmode specific arguments // playmode specific arguments
if emulationMode == emulation.ModePlay { if emulationMode == govern.ModePlay {
opts.ComparisonROM = md.AddString("comparisonROM", "", "ROM to run in parallel for comparison") opts.ComparisonROM = md.AddString("comparisonROM", "", "ROM to run in parallel for comparison")
opts.ComparisonPrefs = md.AddString("comparisonPrefs", "", "preferences for comparison emulation") opts.ComparisonPrefs = md.AddString("comparisonPrefs", "", "preferences for comparison emulation")
opts.Record = md.AddBool("record", false, "record user input to a file") opts.Record = md.AddBool("record", false, "record user input to a file")
@ -308,7 +308,7 @@ func emulate(emulationMode emulation.Mode, md *modalflag.Modes, sync *mainSync)
} }
// debugger specific arguments // debugger specific arguments
if emulationMode == emulation.ModeDebugger { if emulationMode == govern.ModeDebugger {
opts.InitScript = md.AddString("initscript", defInitScript, "script to run on debugger start") opts.InitScript = md.AddString("initscript", defInitScript, "script to run on debugger start")
opts.TermType = md.AddString("term", "IMGUI", "terminal type to use in debug mode: IMGUI, COLOR, PLAIN") opts.TermType = md.AddString("term", "IMGUI", "terminal type to use in debug mode: IMGUI, COLOR, PLAIN")
} else { } else {
@ -348,7 +348,7 @@ func emulate(emulationMode emulation.Mode, md *modalflag.Modes, sync *mainSync)
// prepare new debugger, supplying a debugger.CreateUserInterface function. // prepare new debugger, supplying a debugger.CreateUserInterface function.
// this function will be called by NewDebugger() and in turn will send a // this function will be called by NewDebugger() and in turn will send a
// GUI create message to the main goroutine // GUI create message to the main goroutine
dbg, err := debugger.NewDebugger(opts, func(e emulation.Emulation) (gui.GUI, terminal.Terminal, error) { dbg, err := debugger.NewDebugger(opts, func(e *debugger.Debugger) (gui.GUI, terminal.Terminal, error) {
var term terminal.Terminal var term terminal.Terminal
var scr gui.GUI var scr gui.GUI
@ -402,13 +402,13 @@ func emulate(emulationMode emulation.Mode, md *modalflag.Modes, sync *mainSync)
// a call to performance.RunProfiler() // a call to performance.RunProfiler()
dbgLaunch := func() error { dbgLaunch := func() error {
switch emulationMode { switch emulationMode {
case emulation.ModeDebugger: case govern.ModeDebugger:
err := dbg.StartInDebugMode(md.GetArg(0)) err := dbg.StartInDebugMode(md.GetArg(0))
if err != nil { if err != nil {
return err return err
} }
case emulation.ModePlay: case govern.ModePlay:
err := dbg.StartInPlayMode(md.GetArg(0)) err := dbg.StartInPlayMode(md.GetArg(0))
if err != nil { if err != nil {
return err return err
@ -435,9 +435,9 @@ func emulate(emulationMode emulation.Mode, md *modalflag.Modes, sync *mainSync)
// filename argument for RunProfiler // filename argument for RunProfiler
s := "" s := ""
switch emulationMode { switch emulationMode {
case emulation.ModeDebugger: case govern.ModeDebugger:
s = "debugger" s = "debugger"
case emulation.ModePlay: case govern.ModePlay:
s = "play" s = "play"
} }

View file

@ -17,7 +17,7 @@ package sdlimgui
import ( import (
"github.com/go-gl/gl/v3.2-core/gl" "github.com/go-gl/gl/v3.2-core/gl"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/gui/sdlimgui/shaders" "github.com/jetsetilly/gopher2600/gui/sdlimgui/shaders"
"github.com/jetsetilly/gopher2600/hardware/television/specification" "github.com/jetsetilly/gopher2600/hardware/television/specification"
) )
@ -90,14 +90,14 @@ func (attr *dbgScrHelper) set(img *SdlImgui) {
// end of critical section // end of critical section
// show cursor // show cursor
switch img.emulation.State() { switch img.dbg.State() {
case emulation.Paused: case govern.Paused:
gl.Uniform1i(attr.showCursor, 1) gl.Uniform1i(attr.showCursor, 1)
case emulation.Running: case govern.Running:
gl.Uniform1i(attr.showCursor, 0) gl.Uniform1i(attr.showCursor, 0)
case emulation.Stepping: case govern.Stepping:
gl.Uniform1i(attr.showCursor, 1) gl.Uniform1i(attr.showCursor, 1)
case emulation.Rewinding: case govern.Rewinding:
gl.Uniform1i(attr.showCursor, 1) gl.Uniform1i(attr.showCursor, 1)
} }
} }

View file

@ -19,8 +19,8 @@ import (
"sync/atomic" "sync/atomic"
"github.com/jetsetilly/gopher2600/debugger" "github.com/jetsetilly/gopher2600/debugger"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/disassembly" "github.com/jetsetilly/gopher2600/disassembly"
"github.com/jetsetilly/gopher2600/emulation"
) )
// LazyDebugger lazily accesses Debugger information. // LazyDebugger lazily accesses Debugger information.
@ -31,18 +31,18 @@ type LazyDebugger struct {
liveDisasmEntry atomic.Value // disassembly.Entry liveDisasmEntry atomic.Value // disassembly.Entry
breakpoints atomic.Value // debugger.BreakpointsQuery breakpoints atomic.Value // debugger.BreakpointsQuery
hasChanged atomic.Value // bool hasChanged atomic.Value // bool
state atomic.Value // emulation.State state atomic.Value // govern.State
Quantum debugger.Quantum Quantum debugger.Quantum
LiveDisasmEntry disassembly.Entry LiveDisasmEntry disassembly.Entry
Breakpoints debugger.BreakpointsQuery Breakpoints debugger.BreakpointsQuery
HasChanged bool HasChanged bool
// the emulation.State below is taken at the same time as the reset of the // the govern.State below is taken at the same time as the reset of the
// lazy values. this value should be used in preference to the live // lazy values. this value should be used in preference to the live
// emulation.State() value (which is safe to obtain outside of the lazy // govern.State() value (which is safe to obtain outside of the lazy
// system) when synchronisation is important // system) when synchronisation is important
State emulation.State State govern.State
} }
func newLazyDebugger(val *LazyValues) *LazyDebugger { func newLazyDebugger(val *LazyValues) *LazyDebugger {
@ -78,5 +78,5 @@ func (lz *LazyDebugger) update() {
// load current hasChanged value and unlatch (see push() function) // load current hasChanged value and unlatch (see push() function)
lz.HasChanged = lz.hasChanged.Load().(bool) lz.HasChanged = lz.hasChanged.Load().(bool)
lz.hasChanged.Store(false) lz.hasChanged.Store(false)
lz.State, _ = lz.state.Load().(emulation.State) lz.State, _ = lz.state.Load().(govern.State)
} }

View file

@ -19,7 +19,6 @@ import (
"sync/atomic" "sync/atomic"
"github.com/jetsetilly/gopher2600/debugger" "github.com/jetsetilly/gopher2600/debugger"
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/hardware" "github.com/jetsetilly/gopher2600/hardware"
"github.com/jetsetilly/gopher2600/hardware/television" "github.com/jetsetilly/gopher2600/hardware/television"
) )
@ -28,12 +27,9 @@ import (
// thread to the emulation. Use these values rather than directly accessing // thread to the emulation. Use these values rather than directly accessing
// those exposed by the emulation. // those exposed by the emulation.
type LazyValues struct { type LazyValues struct {
emulation emulation.Emulation dbg *debugger.Debugger
// vcs and dbg are taken from the emulation supplied to SetEmulation()
tv *television.Television tv *television.Television
vcs *hardware.VCS vcs *hardware.VCS
dbg *debugger.Debugger
// pointers to these instances. non-pointer instances trigger the race // pointers to these instances. non-pointer instances trigger the race
// detector for some reason. // detector for some reason.
@ -67,16 +63,12 @@ type LazyValues struct {
} }
// NewLazyValues is the preferred method of initialisation for the Values type. // NewLazyValues is the preferred method of initialisation for the Values type.
func NewLazyValues(e emulation.Emulation) *LazyValues { func NewLazyValues(dbg *debugger.Debugger) *LazyValues {
val := &LazyValues{} val := &LazyValues{}
val.emulation = e val.dbg = dbg
val.tv = e.TV().(*television.Television) val.tv = val.dbg.TV()
val.vcs = e.VCS().(*hardware.VCS) val.vcs = val.dbg.VCS()
switch dbg := e.Debugger().(type) {
case *debugger.Debugger:
val.dbg = dbg
}
val.Debugger = newLazyDebugger(val) val.Debugger = newLazyDebugger(val)
val.CPU = newLazyCPU(val) val.CPU = newLazyCPU(val)
@ -107,7 +99,7 @@ func NewLazyValues(e emulation.Emulation) *LazyValues {
// Refresh lazy values. // Refresh lazy values.
func (val *LazyValues) Refresh() { func (val *LazyValues) Refresh() {
if val.emulation == nil { if val.dbg == nil {
return return
} }
@ -169,7 +161,7 @@ func (val *LazyValues) Refresh() {
// FastRefresh lazy values. Updates only the values that are needed in playmode. // FastRefresh lazy values. Updates only the values that are needed in playmode.
func (val *LazyValues) FastRefresh() { func (val *LazyValues) FastRefresh() {
if val.emulation == nil { if val.dbg == nil {
return return
} }

View file

@ -19,7 +19,7 @@ import (
"sort" "sort"
"github.com/inkyblackness/imgui-go/v4" "github.com/inkyblackness/imgui-go/v4"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
) )
// manager handles windows and menus in the system. // manager handles windows and menus in the system.
@ -209,13 +209,13 @@ func (wm *manager) draw() {
} }
switch wm.img.mode { switch wm.img.mode {
case emulation.ModePlay: case govern.ModePlay:
// playmode draws the screen and other windows that have been listed // playmode draws the screen and other windows that have been listed
// as being safe to draw in playmode // as being safe to draw in playmode
for _, w := range wm.playmodeWindows { for _, w := range wm.playmodeWindows {
w.playmodeDraw() w.playmodeDraw()
} }
case emulation.ModeDebugger: case govern.ModeDebugger:
// see commentary for screenPos in windowManager declaration // see commentary for screenPos in windowManager declaration
wm.screenPos = imgui.WindowPos() wm.screenPos = imgui.WindowPos()

View file

@ -20,7 +20,7 @@ import (
"math" "math"
"github.com/inkyblackness/imgui-go/v4" "github.com/inkyblackness/imgui-go/v4"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/gui/fonts" "github.com/jetsetilly/gopher2600/gui/fonts"
) )
@ -172,7 +172,7 @@ func (wm *manager) drawMenu() {
wdth -= rightJustText(wdth, fmt.Sprintf("%.2fHz", wm.img.lz.TV.Hz), true) wdth -= rightJustText(wdth, fmt.Sprintf("%.2fHz", wm.img.lz.TV.Hz), true)
} }
if wm.img.emulation.State() == emulation.Running { if wm.img.dbg.State() == govern.Running {
if wm.img.lz.TV.ReqFPS < 1.0 { if wm.img.lz.TV.ReqFPS < 1.0 {
wdth -= rightJustText(wdth, "< 1 fps", true) wdth -= rightJustText(wdth, "< 1 fps", true)
} else if math.IsInf(float64(wm.img.lz.TV.ActualFPS), 0) { } else if math.IsInf(float64(wm.img.lz.TV.ActualFPS), 0) {

View file

@ -22,7 +22,7 @@ import (
"strings" "strings"
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/prefs" "github.com/jetsetilly/gopher2600/prefs"
"github.com/jetsetilly/gopher2600/resources" "github.com/jetsetilly/gopher2600/resources"
"github.com/jetsetilly/gopher2600/resources/fs" "github.com/jetsetilly/gopher2600/resources/fs"
@ -77,7 +77,7 @@ func (wm *manager) saveManagerState() (rerr error) {
continue continue
} }
s := fmt.Sprintf("%s%s%s%s%v\n", emulation.ModeDebugger.String(), prefs.KeySep, key, prefs.KeySep, win.debuggerIsOpen()) s := fmt.Sprintf("%s%s%s%s%v\n", govern.ModeDebugger.String(), prefs.KeySep, key, prefs.KeySep, win.debuggerIsOpen())
n, err := fmt.Fprint(f, s) n, err := fmt.Fprint(f, s)
if err != nil { if err != nil {
return curated.Errorf("manager state: %v", err) return curated.Errorf("manager state: %v", err)
@ -94,7 +94,7 @@ func (wm *manager) saveManagerState() (rerr error) {
continue continue
} }
s := fmt.Sprintf("%s%s%s%s%v\n", emulation.ModePlay.String(), prefs.KeySep, key, prefs.KeySep, win.playmodeIsOpen()) s := fmt.Sprintf("%s%s%s%s%v\n", govern.ModePlay.String(), prefs.KeySep, key, prefs.KeySep, win.playmodeIsOpen())
n, err := fmt.Fprint(f, s) n, err := fmt.Fprint(f, s)
if err != nil { if err != nil {
return curated.Errorf("manager state: %v", err) return curated.Errorf("manager state: %v", err)
@ -159,13 +159,13 @@ func (wm *manager) loadManagerState() (rerr error) {
k := spt[1] k := spt[1]
v := spt[2] v := spt[2]
if m == emulation.ModeDebugger.String() { if m == govern.ModeDebugger.String() {
if w, ok := wm.debuggerWindows[k]; ok { if w, ok := wm.debuggerWindows[k]; ok {
w.debuggerSetOpen(strings.ToUpper(v) == "TRUE") w.debuggerSetOpen(strings.ToUpper(v) == "TRUE")
} }
} }
if m == emulation.ModePlay.String() { if m == govern.ModePlay.String() {
if w, ok := wm.playmodeWindows[k]; ok { if w, ok := wm.playmodeWindows[k]; ok {
w.playmodeSetOpen(strings.ToUpper(v) == "TRUE") w.playmodeSetOpen(strings.ToUpper(v) == "TRUE")
} }

View file

@ -88,7 +88,7 @@ func newPlayScr(img *SdlImgui) *playScr {
rightAlign: true, rightAlign: true,
}, },
emulationEvent: emulationEventNotification{ emulationEvent: emulationEventNotification{
emulation: img.emulation, emulation: img.dbg,
}, },
} }

View file

@ -19,7 +19,8 @@ import (
"fmt" "fmt"
"github.com/inkyblackness/imgui-go/v4" "github.com/inkyblackness/imgui-go/v4"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/gui/fonts" "github.com/jetsetilly/gopher2600/gui/fonts"
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper" "github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper"
"github.com/jetsetilly/gopher2600/hardware/riot/ports/plugging" "github.com/jetsetilly/gopher2600/hardware/riot/ports/plugging"
@ -118,9 +119,9 @@ func (pn *peripheralNotification) draw(win *playScr) {
// emulationEventNotification is used to draw an indicator on the screen for // emulationEventNotification is used to draw an indicator on the screen for
// events defined in the emulation package. // events defined in the emulation package.
type emulationEventNotification struct { type emulationEventNotification struct {
emulation emulation.Emulation emulation *debugger.Debugger
open bool open bool
currentEvent emulation.Event currentEvent govern.Event
frames int frames int
// audio mute is handled differently to other events. we want the icon for // audio mute is handled differently to other events. we want the icon for
@ -130,18 +131,18 @@ type emulationEventNotification struct {
mute bool mute bool
} }
func (ee *emulationEventNotification) set(event emulation.Event) { func (ee *emulationEventNotification) set(event govern.Event) {
ee.currentEvent = event ee.currentEvent = event
ee.open = true ee.open = true
ee.frames = notificationDurationEvent ee.frames = notificationDurationEvent
switch event { switch event {
case emulation.EventRun: case govern.EventRun:
ee.frames = notificationDurationEventRun ee.frames = notificationDurationEventRun
case emulation.EventScreenshot: case govern.EventScreenshot:
ee.frames = notificationDurationScreenshot ee.frames = notificationDurationScreenshot
case emulation.EventMute: case govern.EventMute:
ee.mute = true ee.mute = true
case emulation.EventUnmute: case govern.EventUnmute:
ee.mute = false ee.mute = false
} }
} }
@ -155,16 +156,16 @@ func (ee *emulationEventNotification) tick() {
if ee.frames == 0 { if ee.frames == 0 {
// if emulation is paused then force the current event to EventPause // if emulation is paused then force the current event to EventPause
if ee.emulation.State() == emulation.Paused { if ee.emulation.State() == govern.Paused {
ee.currentEvent = emulation.EventPause ee.currentEvent = govern.EventPause
} }
// special handling of open when current event is EventPause or if mute // special handling of open when current event is EventPause or if mute
// is enabled // is enabled
if ee.currentEvent != emulation.EventPause { if ee.currentEvent != govern.EventPause {
if ee.mute { if ee.mute {
ee.open = true ee.open = true
ee.currentEvent = emulation.EventMute ee.currentEvent = govern.EventMute
} else { } else {
ee.open = false ee.open = false
} }
@ -196,23 +197,23 @@ func (ee *emulationEventNotification) draw(win *playScr, hosted bool) {
} }
switch ee.currentEvent { switch ee.currentEvent {
case emulation.EventInitialising: case govern.EventInitialising:
imgui.Text("") imgui.Text("")
case emulation.EventPause: case govern.EventPause:
imgui.Text(string(fonts.EmulationPause)) imgui.Text(string(fonts.EmulationPause))
case emulation.EventRun: case govern.EventRun:
imgui.Text(string(fonts.EmulationRun)) imgui.Text(string(fonts.EmulationRun))
case emulation.EventRewindBack: case govern.EventRewindBack:
imgui.Text(string(fonts.EmulationRewindBack)) imgui.Text(string(fonts.EmulationRewindBack))
case emulation.EventRewindFoward: case govern.EventRewindFoward:
imgui.Text(string(fonts.EmulationRewindForward)) imgui.Text(string(fonts.EmulationRewindForward))
case emulation.EventRewindAtStart: case govern.EventRewindAtStart:
imgui.Text(string(fonts.EmulationRewindAtStart)) imgui.Text(string(fonts.EmulationRewindAtStart))
case emulation.EventRewindAtEnd: case govern.EventRewindAtEnd:
imgui.Text(string(fonts.EmulationRewindAtEnd)) imgui.Text(string(fonts.EmulationRewindAtEnd))
case emulation.EventScreenshot: case govern.EventScreenshot:
imgui.Text(string(fonts.Camera)) imgui.Text(string(fonts.Camera))
case emulation.EventMute: case govern.EventMute:
if hosted || win.img.prefs.audioMuteNotification.Get().(bool) { if hosted || win.img.prefs.audioMuteNotification.Get().(bool) {
imgui.Text(string(fonts.AudioMute)) imgui.Text(string(fonts.AudioMute))
} }

View file

@ -18,7 +18,7 @@ package sdlimgui
import ( import (
"time" "time"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/veandco/go-sdl2/sdl" "github.com/veandco/go-sdl2/sdl"
) )
@ -128,7 +128,7 @@ func (pol *polling) wait() sdl.Event {
} else { } else {
working := pol.awake || working := pol.awake ||
pol.img.lz.Debugger.HasChanged || pol.img.lz.Debugger.HasChanged ||
pol.img.emulation.State() != emulation.Paused || pol.img.dbg.State() != govern.Paused ||
pol.img.wm.dbgScr.crtPreview pol.img.wm.dbgScr.crtPreview
if working { if working {

View file

@ -17,7 +17,7 @@ package sdlimgui
import ( import (
"fmt" "fmt"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/prefs" "github.com/jetsetilly/gopher2600/prefs"
"github.com/jetsetilly/gopher2600/resources" "github.com/jetsetilly/gopher2600/resources"
) )
@ -236,11 +236,11 @@ func (p *preferences) loadWindowPreferences() error {
var group string var group string
switch p.img.mode { switch p.img.mode {
case emulation.ModeNone: case govern.ModeNone:
p.img.plt.window.Hide() p.img.plt.window.Hide()
case emulation.ModeDebugger: case govern.ModeDebugger:
group = "sdlimgui.debugger" group = "sdlimgui.debugger"
case emulation.ModePlay: case govern.ModePlay:
group = "sdlimgui.playmode" group = "sdlimgui.playmode"
default: default:
panic(fmt.Sprintf("cannot set window mode for unsupported emulation mode (%v)", p.img.mode)) panic(fmt.Sprintf("cannot set window mode for unsupported emulation mode (%v)", p.img.mode))

View file

@ -20,7 +20,7 @@ import (
"github.com/jetsetilly/gopher2600/bots" "github.com/jetsetilly/gopher2600/bots"
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/gui" "github.com/jetsetilly/gopher2600/gui"
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper" "github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper"
"github.com/jetsetilly/gopher2600/hardware/riot/ports/plugging" "github.com/jetsetilly/gopher2600/hardware/riot/ports/plugging"
@ -54,7 +54,7 @@ func (img *SdlImgui) serviceSetFeature(request featureRequest) {
case gui.ReqSetEmulationMode: case gui.ReqSetEmulationMode:
err = argLen(request.args, 1) err = argLen(request.args, 1)
if err == nil { if err == nil {
img.setEmulationMode(request.args[0].(emulation.Mode)) img.setEmulationMode(request.args[0].(govern.Mode))
} }
case gui.ReqEnd: case gui.ReqEnd:
@ -106,7 +106,7 @@ func (img *SdlImgui) serviceSetFeature(request featureRequest) {
if img.isPlaymode() { if img.isPlaymode() {
err = argLen(request.args, 1) err = argLen(request.args, 1)
if err == nil { if err == nil {
img.playScr.emulationEvent.set(request.args[0].(emulation.Event)) img.playScr.emulationEvent.set(request.args[0].(govern.Event))
} }
} }

View file

@ -20,7 +20,7 @@ import (
"image/color" "image/color"
"sync" "sync"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper" "github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper"
"github.com/jetsetilly/gopher2600/hardware/television" "github.com/jetsetilly/gopher2600/hardware/television"
"github.com/jetsetilly/gopher2600/hardware/television/signal" "github.com/jetsetilly/gopher2600/hardware/television/signal"
@ -360,14 +360,14 @@ func (scr *screen) NewFrame(frameInfo television.FrameInfo) error {
} }
if scr.crit.monitorSync && scr.crit.monitorSyncInRange { if scr.crit.monitorSync && scr.crit.monitorSyncInRange {
switch scr.img.emulation.State() { switch scr.img.dbg.State() {
case emulation.Rewinding: case govern.Rewinding:
fallthrough fallthrough
case emulation.Paused: case govern.Paused:
scr.crit.renderIdx = scr.crit.plotIdx scr.crit.renderIdx = scr.crit.plotIdx
scr.crit.prevRenderIdx = scr.crit.plotIdx scr.crit.prevRenderIdx = scr.crit.plotIdx
scr.crit.bufferUsed = len(scr.crit.bufferPixels) scr.crit.bufferUsed = len(scr.crit.bufferPixels)
case emulation.Running: case govern.Running:
if scr.crit.bufferUsed > 0 { if scr.crit.bufferUsed > 0 {
scr.crit.bufferUsed-- scr.crit.bufferUsed--
} }
@ -622,7 +622,7 @@ func (scr *screen) copyPixelsPlaymode() {
// poor results for one frame kernels (depending on the ROM and what is // poor results for one frame kernels (depending on the ROM and what is
// happening on the screen at the time of the pause ) and will be // happening on the screen at the time of the pause ) and will be
// sub-optimal for three frame kernels in almost all cases. // sub-optimal for three frame kernels in almost all cases.
if scr.img.emulation.State() == emulation.Paused { if scr.img.dbg.State() == govern.Paused {
activePause := scr.img.prefs.activePause.Get().(bool) activePause := scr.img.prefs.activePause.Get().(bool)
if scr.crit.pauseFrame || !activePause { if scr.crit.pauseFrame || !activePause {
copy(scr.crit.pixels.Pix, scr.crit.bufferPixels[scr.crit.renderIdx].Pix) copy(scr.crit.pixels.Pix, scr.crit.bufferPixels[scr.crit.renderIdx].Pix)

View file

@ -21,8 +21,8 @@ import (
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/debugger" "github.com/jetsetilly/gopher2600/debugger"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/debugger/terminal" "github.com/jetsetilly/gopher2600/debugger/terminal"
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/gui/crt" "github.com/jetsetilly/gopher2600/gui/crt"
"github.com/jetsetilly/gopher2600/gui/sdlaudio" "github.com/jetsetilly/gopher2600/gui/sdlaudio"
"github.com/jetsetilly/gopher2600/gui/sdlimgui/lazyvalues" "github.com/jetsetilly/gopher2600/gui/sdlimgui/lazyvalues"
@ -63,16 +63,13 @@ type SdlImgui struct {
// allow sufficient time to close the font size selector combo box // allow sufficient time to close the font size selector combo box
resetFonts int resetFonts int
// parent emulation. should be set via setEmulation() only
emulation emulation.Emulation
// the current mode of the underlying // the current mode of the underlying
mode emulation.Mode mode govern.Mode
// taken from the emulation field and assigned in the setEmulation() function // taken from the emulation field and assigned in the setEmulation() function
dbg *debugger.Debugger
tv *television.Television tv *television.Television
vcs *hardware.VCS vcs *hardware.VCS
dbg *debugger.Debugger
userinput chan userinput.Event userinput chan userinput.Event
// lazy value system allows safe access to the debugger/emulation from the // lazy value system allows safe access to the debugger/emulation from the
@ -127,21 +124,17 @@ type SdlImgui struct {
// NewSdlImgui is the preferred method of initialisation for type SdlImgui // NewSdlImgui is the preferred method of initialisation for type SdlImgui
// //
// MUST ONLY be called from the gui thread. // MUST ONLY be called from the gui thread.
func NewSdlImgui(e emulation.Emulation) (*SdlImgui, error) { func NewSdlImgui(dbg *debugger.Debugger) (*SdlImgui, error) {
img := &SdlImgui{ img := &SdlImgui{
context: imgui.CreateContext(nil), context: imgui.CreateContext(nil),
io: imgui.CurrentIO(), io: imgui.CurrentIO(),
postRenderFunctions: make(chan func(), 100), postRenderFunctions: make(chan func(), 100),
} }
img.emulation = e img.dbg = dbg
img.tv = e.TV().(*television.Television) img.tv = img.dbg.TV()
img.vcs = e.VCS().(*hardware.VCS) img.vcs = img.dbg.VCS()
switch dbg := e.Debugger().(type) { img.userinput = img.dbg.UserInput()
case *debugger.Debugger:
img.dbg = dbg
}
img.userinput = e.UserInput()
// path to dear imgui ini file // path to dear imgui ini file
iniPath, err := resources.JoinPath(imguiIniFile) iniPath, err := resources.JoinPath(imguiIniFile)
@ -163,7 +156,7 @@ func NewSdlImgui(e emulation.Emulation) (*SdlImgui, error) {
return nil, curated.Errorf("sdlimgui: %v", err) return nil, curated.Errorf("sdlimgui: %v", err)
} }
img.lz = lazyvalues.NewLazyValues(img.emulation) img.lz = lazyvalues.NewLazyValues(img.dbg)
img.screen = newScreen(img) img.screen = newScreen(img)
img.term = newTerm() img.term = newTerm()
@ -298,18 +291,18 @@ func (img *SdlImgui) end() {
// draw gui. called from service loop. // draw gui. called from service loop.
func (img *SdlImgui) draw() { func (img *SdlImgui) draw() {
if img.mode == emulation.ModeNone { if img.mode == govern.ModeNone {
return return
} }
if img.emulation.State() == emulation.EmulatorStart { if img.dbg.State() == govern.EmulatorStart {
return return
} }
imgui.PushFont(img.glsl.fonts.defaultFont) imgui.PushFont(img.glsl.fonts.defaultFont)
defer imgui.PopFont() defer imgui.PopFont()
if img.mode == emulation.ModePlay { if img.mode == govern.ModePlay {
img.playScr.draw() img.playScr.draw()
} }
@ -320,14 +313,14 @@ func (img *SdlImgui) draw() {
// is the gui in playmode or not. thread safe. called from emulation thread // is the gui in playmode or not. thread safe. called from emulation thread
// and gui thread. // and gui thread.
func (img *SdlImgui) isPlaymode() bool { func (img *SdlImgui) isPlaymode() bool {
return img.mode == emulation.ModePlay return img.mode == govern.ModePlay
} }
// set emulation and handle the changeover gracefully. this includes the saving // set emulation and handle the changeover gracefully. this includes the saving
// and loading of preference groups. // and loading of preference groups.
// //
// should only be called from gui thread. // should only be called from gui thread.
func (img *SdlImgui) setEmulationMode(mode emulation.Mode) error { func (img *SdlImgui) setEmulationMode(mode govern.Mode) error {
// release captured mouse before switching emulation modes. if we don't do // release captured mouse before switching emulation modes. if we don't do
// this then the capture state will remain if we flip back to the emulation // this then the capture state will remain if we flip back to the emulation
// mode later. at this point the captured mouse can cause confusion // mode later. at this point the captured mouse can cause confusion
@ -337,12 +330,12 @@ func (img *SdlImgui) setEmulationMode(mode emulation.Mode) error {
img.prefs.loadWindowPreferences() img.prefs.loadWindowPreferences()
switch mode { switch mode {
case emulation.ModeDebugger: case govern.ModeDebugger:
img.screen.clearTextureRenderers() img.screen.clearTextureRenderers()
img.screen.addTextureRenderer(img.wm.dbgScr) img.screen.addTextureRenderer(img.wm.dbgScr)
img.plt.window.Show() img.plt.window.Show()
case emulation.ModePlay: case govern.ModePlay:
img.screen.clearTextureRenderers() img.screen.clearTextureRenderers()
img.screen.addTextureRenderer(img.playScr) img.screen.addTextureRenderer(img.playScr)
img.plt.window.Show() img.plt.window.Show()
@ -379,9 +372,9 @@ func (img *SdlImgui) setAudioMute() {
if img.isPlaymode() { if img.isPlaymode() {
mute = img.prefs.audioMutePlaymode.Get().(bool) mute = img.prefs.audioMutePlaymode.Get().(bool)
if mute { if mute {
img.playScr.emulationEvent.set(emulation.EventMute) img.playScr.emulationEvent.set(govern.EventMute)
} else { } else {
img.playScr.emulationEvent.set(emulation.EventUnmute) img.playScr.emulationEvent.set(govern.EventUnmute)
} }
img.vcs.RIOT.Ports.MutePeripherals(mute) img.vcs.RIOT.Ports.MutePeripherals(mute)
} else { } else {

View file

@ -18,7 +18,7 @@ package sdlimgui
import ( import (
"time" "time"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/hardware/riot/ports/plugging" "github.com/jetsetilly/gopher2600/hardware/riot/ports/plugging"
"github.com/jetsetilly/gopher2600/logger" "github.com/jetsetilly/gopher2600/logger"
"github.com/jetsetilly/gopher2600/userinput" "github.com/jetsetilly/gopher2600/userinput"
@ -43,9 +43,9 @@ func (img *SdlImgui) Service() {
// refresh lazy values // refresh lazy values
switch img.mode { switch img.mode {
case emulation.ModeDebugger: case govern.ModeDebugger:
img.lz.Refresh() img.lz.Refresh()
case emulation.ModePlay: case govern.ModePlay:
img.lz.FastRefresh() img.lz.FastRefresh()
} }
@ -141,7 +141,7 @@ func (img *SdlImgui) Service() {
} }
img.io.AddMouseWheelDelta(deltaX/4, deltaY/4) img.io.AddMouseWheelDelta(deltaX/4, deltaY/4)
if img.mode != emulation.ModePlay || !img.wm.playmodeWindows[winSelectROMID].playmodeIsOpen() { if img.mode != govern.ModePlay || !img.wm.playmodeWindows[winSelectROMID].playmodeIsOpen() {
select { select {
case img.userinput <- userinput.EventMouseWheel{Delta: deltaY}: case img.userinput <- userinput.EventMouseWheel{Delta: deltaY}:
default: default:
@ -386,9 +386,9 @@ func (img *SdlImgui) serviceKeyboard(ev *sdl.KeyboardEvent) {
case sdl.SCANCODE_GRAVE: case sdl.SCANCODE_GRAVE:
if img.isPlaymode() { if img.isPlaymode() {
img.emulation.SetFeature(emulation.ReqSetMode, emulation.ModeDebugger) img.dbg.SetFeature(govern.ReqSetMode, govern.ModeDebugger)
} else { } else {
img.emulation.SetFeature(emulation.ReqSetMode, emulation.ModePlay) img.dbg.SetFeature(govern.ReqSetMode, govern.ModePlay)
} }
case sdl.SCANCODE_F8: case sdl.SCANCODE_F8:
@ -413,7 +413,7 @@ func (img *SdlImgui) serviceKeyboard(ev *sdl.KeyboardEvent) {
img.glsl.shaders[playscrShaderID].(*playscrShader).scheduleScreenshot(modeSingle) img.glsl.shaders[playscrShaderID].(*playscrShader).scheduleScreenshot(modeSingle)
} }
img.playScr.emulationEvent.set(emulation.EventScreenshot) img.playScr.emulationEvent.set(govern.EventScreenshot)
case sdl.SCANCODE_F14: case sdl.SCANCODE_F14:
fallthrough fallthrough
@ -425,16 +425,16 @@ func (img *SdlImgui) serviceKeyboard(ev *sdl.KeyboardEvent) {
case sdl.SCANCODE_PAUSE: case sdl.SCANCODE_PAUSE:
if img.isPlaymode() { if img.isPlaymode() {
var err error var err error
if img.emulation.State() == emulation.Paused { if img.dbg.State() == govern.Paused {
err = img.emulation.SetFeature(emulation.ReqSetPause, false) err = img.dbg.SetFeature(govern.ReqSetPause, false)
} else { } else {
err = img.emulation.SetFeature(emulation.ReqSetPause, true) err = img.dbg.SetFeature(govern.ReqSetPause, true)
} }
if err != nil { if err != nil {
logger.Logf("sdlimgui", err.Error()) logger.Logf("sdlimgui", err.Error())
} }
} else { } else {
if img.emulation.State() == emulation.Paused { if img.dbg.State() == govern.Paused {
img.term.pushCommand("RUN") img.term.pushCommand("RUN")
} else { } else {
img.term.pushCommand("HALT") img.term.pushCommand("HALT")

View file

@ -21,7 +21,7 @@ import (
"time" "time"
"github.com/jetsetilly/gopher2600/debugger" "github.com/jetsetilly/gopher2600/debugger"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/gui/fonts" "github.com/jetsetilly/gopher2600/gui/fonts"
"github.com/inkyblackness/imgui-go/v4" "github.com/inkyblackness/imgui-go/v4"
@ -120,7 +120,7 @@ func (win *winControl) draw() {
func (win *winControl) drawRunButton() { func (win *winControl) drawRunButton() {
runDim := imgui.Vec2{X: imguiRemainingWinWidth(), Y: imgui.FrameHeight()} runDim := imgui.Vec2{X: imguiRemainingWinWidth(), Y: imgui.FrameHeight()}
if win.img.emulation.State() == emulation.Running { if win.img.dbg.State() == govern.Running {
if imguiColourButton(win.img.cols.False, fmt.Sprintf("%c Halt", fonts.Halt), runDim) { if imguiColourButton(win.img.cols.False, fmt.Sprintf("%c Halt", fonts.Halt), runDim) {
win.img.term.pushCommand("HALT") win.img.term.pushCommand("HALT")
} }
@ -229,7 +229,7 @@ func (win *winControl) drawFPS() {
} }
imgui.Spacing() imgui.Spacing()
if win.img.emulation.State() == emulation.Running { if win.img.dbg.State() == govern.Running {
if win.img.lz.TV.ActualFPS <= win.img.lz.TV.ReqFPS*0.95 { if win.img.lz.TV.ActualFPS <= win.img.lz.TV.ReqFPS*0.95 {
imgui.Text("running below requested FPS") imgui.Text("running below requested FPS")
} else if win.img.lz.TV.ActualFPS > win.img.lz.TV.ReqFPS*1.05 { } else if win.img.lz.TV.ActualFPS > win.img.lz.TV.ReqFPS*1.05 {
@ -253,13 +253,13 @@ func (win *winControl) drawMouseCapture() {
if win.img.wm.dbgScr.isCaptured { if win.img.wm.dbgScr.isCaptured {
imgui.AlignTextToFramePadding() imgui.AlignTextToFramePadding()
label := "RMB to release input" label := "RMB to release input"
if win.img.emulation.State() == emulation.Running { if win.img.dbg.State() == govern.Running {
label = "RMB to halt & release input" label = "RMB to halt & release input"
} }
imgui.Text(label) imgui.Text(label)
} else { } else {
label := "Capture input & run" label := "Capture input & run"
if win.img.emulation.State() == emulation.Running { if win.img.dbg.State() == govern.Running {
label = "Capture input & continue" label = "Capture input & continue"
} }
if imgui.Button(label) { if imgui.Button(label) {

View file

@ -20,7 +20,7 @@ import (
"github.com/inkyblackness/imgui-go/v4" "github.com/inkyblackness/imgui-go/v4"
"github.com/jetsetilly/gopher2600/coprocessor/disassembly" "github.com/jetsetilly/gopher2600/coprocessor/disassembly"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/gui/fonts" "github.com/jetsetilly/gopher2600/gui/fonts"
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/arm" "github.com/jetsetilly/gopher2600/hardware/memory/cartridge/arm"
) )
@ -114,7 +114,7 @@ func (win *winCoProcDisasm) draw() {
if imgui.Checkbox("Disassembly Enabled", &isEnabled) { if imgui.Checkbox("Disassembly Enabled", &isEnabled) {
win.img.dbg.PushRawEvent(func() { win.img.dbg.PushRawEvent(func() {
win.img.dbg.CoProcDisasm.Enable(isEnabled) win.img.dbg.CoProcDisasm.Enable(isEnabled)
if win.img.emulation.State() != emulation.Running { if win.img.dbg.State() != govern.Running {
// rerun the last two frames in order to gather as much disasm // rerun the last two frames in order to gather as much disasm
// information as possible. // information as possible.
win.img.dbg.RerunLastNFrames(2) win.img.dbg.RerunLastNFrames(2)

View file

@ -21,8 +21,8 @@ import (
"github.com/go-gl/gl/v3.2-core/gl" "github.com/go-gl/gl/v3.2-core/gl"
"github.com/inkyblackness/imgui-go/v4" "github.com/inkyblackness/imgui-go/v4"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/disassembly" "github.com/jetsetilly/gopher2600/disassembly"
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper" "github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper"
"github.com/jetsetilly/gopher2600/hardware/memory/vcs" "github.com/jetsetilly/gopher2600/hardware/memory/vcs"
"github.com/jetsetilly/gopher2600/hardware/television/coords" "github.com/jetsetilly/gopher2600/hardware/television/coords"
@ -254,7 +254,7 @@ func (win *winDbgScr) draw() {
if imgui.IsWindowFocused() && imageHovered { if imgui.IsWindowFocused() && imageHovered {
// mouse click will cause the rewind goto coords to run only when the // mouse click will cause the rewind goto coords to run only when the
// emulation is paused // emulation is paused
if win.img.emulation.State() == emulation.Paused { if win.img.dbg.State() == govern.Paused {
if imgui.IsMouseDown(0) { if imgui.IsMouseDown(0) {
coords := coords.TelevisionCoords{ coords := coords.TelevisionCoords{
Frame: win.img.lz.TV.Coords.Frame, Frame: win.img.lz.TV.Coords.Frame,
@ -464,7 +464,7 @@ func (win *winDbgScr) drawReflectionTooltip() {
imguiSeparator() imguiSeparator()
// if mouse is over a pixel from the previous frame then show nothing except a note // if mouse is over a pixel from the previous frame then show nothing except a note
if win.img.emulation.State() == emulation.Paused { if win.img.dbg.State() == govern.Paused {
if win.mouse.scanline > win.img.screen.crit.lastScanline || if win.mouse.scanline > win.img.screen.crit.lastScanline ||
(win.mouse.scanline == win.img.screen.crit.lastScanline && win.mouse.clock > win.img.screen.crit.lastClock) { (win.mouse.scanline == win.img.screen.crit.lastScanline && win.mouse.clock > win.img.screen.crit.lastClock) {
imgui.Text("From previous frame") imgui.Text("From previous frame")

View file

@ -18,8 +18,8 @@ package sdlimgui
import ( import (
"fmt" "fmt"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/disassembly" "github.com/jetsetilly/gopher2600/disassembly"
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/gui/fonts" "github.com/jetsetilly/gopher2600/gui/fonts"
"github.com/jetsetilly/gopher2600/hardware/memory/memorymap" "github.com/jetsetilly/gopher2600/hardware/memory/memorymap"
@ -42,7 +42,7 @@ type winDisasm struct {
img *SdlImgui img *SdlImgui
// more recently seen emulation state // more recently seen emulation state
lastSeenState emulation.State lastSeenState govern.State
lastSeenPC uint16 lastSeenPC uint16
// height of options line at bottom of window. valid after first frame // height of options line at bottom of window. valid after first frame
@ -130,10 +130,10 @@ func (win *winDisasm) draw() {
// followCPU is set; or the PC has changed (this is because the state // followCPU is set; or the PC has changed (this is because the state
// change might be missed) // change might be missed)
// //
// using the lazy emulation.State value rather than the live state - the // using the lazy govern.State value rather than the live state - the
// live state can cause synchronisation problems meaning focus is lost // live state can cause synchronisation problems meaning focus is lost
if win.followCPU { if win.followCPU {
if (win.img.lz.Debugger.State == emulation.Paused && win.lastSeenState != emulation.Paused) || if (win.img.lz.Debugger.State == govern.Paused && win.lastSeenState != govern.Paused) ||
win.img.lz.CPU.PC.Address() != win.lastSeenPC { win.img.lz.CPU.PC.Address() != win.lastSeenPC {
win.focusOnAddr = true win.focusOnAddr = true

View file

@ -17,7 +17,7 @@ package sdlimgui
import ( import (
"github.com/inkyblackness/imgui-go/v4" "github.com/inkyblackness/imgui-go/v4"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/logger" "github.com/jetsetilly/gopher2600/logger"
) )
@ -76,7 +76,7 @@ func (win *winLog) draw() {
} }
// very simple conditions to scroll to the bottom // very simple conditions to scroll to the bottom
if win.scrollToBottom || win.img.emulation.State() == emulation.Running { if win.scrollToBottom || win.img.dbg.State() == govern.Running {
win.scrollToBottom = false win.scrollToBottom = false
imgui.SetScrollHereY(0.0) imgui.SetScrollHereY(0.0)
} }

View file

@ -19,7 +19,7 @@ import (
"fmt" "fmt"
"github.com/inkyblackness/imgui-go/v4" "github.com/inkyblackness/imgui-go/v4"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/gui/fonts" "github.com/jetsetilly/gopher2600/gui/fonts"
"github.com/jetsetilly/gopher2600/logger" "github.com/jetsetilly/gopher2600/logger"
) )
@ -106,7 +106,7 @@ func (win *winPrefs) draw() {
imgui.EndTabItem() imgui.EndTabItem()
} }
if win.img.mode == emulation.ModeDebugger { if win.img.mode == govern.ModeDebugger {
if imgui.BeginTabItem("Debugger") { if imgui.BeginTabItem("Debugger") {
win.drawDebuggerTab() win.drawDebuggerTab()
imgui.EndTabItem() imgui.EndTabItem()
@ -418,9 +418,9 @@ func (win *winPrefs) drawVCS() {
var warning bool var warning bool
switch win.img.mode { switch win.img.mode {
case emulation.ModePlay: case govern.ModePlay:
warning = win.img.prefs.audioMutePlaymode.Get().(bool) warning = win.img.prefs.audioMutePlaymode.Get().(bool)
case emulation.ModeDebugger: case govern.ModeDebugger:
warning = win.img.prefs.audioMuteDebugger.Get().(bool) warning = win.img.prefs.audioMuteDebugger.Get().(bool)
} }
@ -587,7 +587,7 @@ func (win *winPrefs) drawDiskButtons() {
logger.Logf("sdlimgui", "could not save (rewind) preferences: %v", err) logger.Logf("sdlimgui", "could not save (rewind) preferences: %v", err)
} }
if win.img.mode == emulation.ModeDebugger { if win.img.mode == govern.ModeDebugger {
err = win.img.dbg.Disasm.Prefs.Save() err = win.img.dbg.Disasm.Prefs.Save()
if err != nil { if err != nil {
logger.Logf("sdlimgui", "could not save (disasm) preferences: %v", err) logger.Logf("sdlimgui", "could not save (disasm) preferences: %v", err)
@ -636,7 +636,7 @@ func (win *winPrefs) drawDiskButtons() {
logger.Logf("sdlimgui", "could not restore (rewind) preferences: %v", err) logger.Logf("sdlimgui", "could not restore (rewind) preferences: %v", err)
} }
if win.img.mode == emulation.ModeDebugger { if win.img.mode == govern.ModeDebugger {
err = win.img.dbg.Disasm.Prefs.Load() err = win.img.dbg.Disasm.Prefs.Load()
if err != nil { if err != nil {
logger.Logf("sdlimgui", "could not restore (disasm) preferences: %v", err) logger.Logf("sdlimgui", "could not restore (disasm) preferences: %v", err)

View file

@ -20,8 +20,8 @@ import (
"os" "os"
"strings" "strings"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/debugger/terminal" "github.com/jetsetilly/gopher2600/debugger/terminal"
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/gui/fonts" "github.com/jetsetilly/gopher2600/gui/fonts"
"github.com/jetsetilly/gopher2600/logger" "github.com/jetsetilly/gopher2600/logger"
"github.com/jetsetilly/gopher2600/resources/unique" "github.com/jetsetilly/gopher2600/resources/unique"
@ -175,7 +175,7 @@ func (win *winTerm) debuggerDraw() {
// the prompt in the terminal should show the disassembly for the // the prompt in the terminal should show the disassembly for the
// instruction the PC is *currently* on. in other words, the // instruction the PC is *currently* on. in other words, the
// disassembly for the inesturction to be executed *next* // disassembly for the inesturction to be executed *next*
if win.img.emulation.State() == emulation.Running { if win.img.dbg.State() == govern.Running {
res := win.img.lz.Debugger.LiveDisasmEntry res := win.img.lz.Debugger.LiveDisasmEntry
imgui.Text(res.String()) imgui.Text(res.String())
if !win.img.lz.Debugger.LiveDisasmEntry.Result.Final { if !win.img.lz.Debugger.LiveDisasmEntry.Result.Final {

View file

@ -19,7 +19,7 @@ import (
"fmt" "fmt"
"github.com/inkyblackness/imgui-go/v4" "github.com/inkyblackness/imgui-go/v4"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/gui/fonts" "github.com/jetsetilly/gopher2600/gui/fonts"
"github.com/jetsetilly/gopher2600/hardware/television/coords" "github.com/jetsetilly/gopher2600/hardware/television/coords"
"github.com/jetsetilly/gopher2600/tracker" "github.com/jetsetilly/gopher2600/tracker"
@ -265,7 +265,7 @@ func (win *winTracker) draw() {
imgui.EndTable() imgui.EndTable()
if win.img.emulation.State() == emulation.Running { if win.img.dbg.State() == govern.Running {
imgui.SetScrollHereY(1.0) imgui.SetScrollHereY(1.0)
} }
} }

View file

@ -15,6 +15,7 @@
package gui package gui
// Stub is a type of convenience that implements the GUI interface.
type Stub struct{} type Stub struct{}
// SetFeature implements the GUI interface. // SetFeature implements the GUI interface.

View file

@ -17,7 +17,7 @@ package hardware
import ( import (
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
) )
// While the continueCheck() function only runs at the end of a CPU instruction // While the continueCheck() function only runs at the end of a CPU instruction
@ -32,19 +32,19 @@ import (
// if performanceFilter >= hardware.PerfomrmanceBrake { // if performanceFilter >= hardware.PerfomrmanceBrake {
// performanceFilter = 0 // performanceFilter = 0
// if end_condition == true { // if end_condition == true {
// return emulation.Ending, nill // return govern.Ending, nill
// } // }
// } // }
// return emulation.Running, nill // return govern.Running, nill
// //
const PerformanceBrake = 100 const PerformanceBrake = 100
// Run sets the emulation running as quickly as possible. continuteCheck() // Run sets the emulation running as quickly as possible. continuteCheck()
// should return false when an external event (eg. a GUI event) indicates that // should return false when an external event (eg. a GUI event) indicates that
// the emulation should stop. // the emulation should stop.
func (vcs *VCS) Run(continueCheck func() (emulation.State, error)) error { func (vcs *VCS) Run(continueCheck func() (govern.State, error)) error {
if continueCheck == nil { if continueCheck == nil {
continueCheck = func() (emulation.State, error) { return emulation.Running, nil } continueCheck = func() (govern.State, error) { return govern.Running, nil }
} }
// see the equivalient videoCycle() in the VCS.Step() function for an // see the equivalient videoCycle() in the VCS.Step() function for an
@ -83,16 +83,16 @@ func (vcs *VCS) Run(continueCheck func() (emulation.State, error)) error {
var err error var err error
state := emulation.Running state := govern.Running
for state != emulation.Ending { for state != govern.Ending {
switch state { switch state {
case emulation.Running: case govern.Running:
err := vcs.CPU.ExecuteInstruction(videoCycle) err := vcs.CPU.ExecuteInstruction(videoCycle)
if err != nil { if err != nil {
return err return err
} }
case emulation.Paused: case govern.Paused:
default: default:
return curated.Errorf("vcs: unsupported emulation state (%d) in Run() function", state) return curated.Errorf("vcs: unsupported emulation state (%d) in Run() function", state)
} }
@ -109,16 +109,16 @@ func (vcs *VCS) Run(continueCheck func() (emulation.State, error)) error {
// RunForFrameCount sets emulator running for the specified number of frames. // RunForFrameCount sets emulator running for the specified number of frames.
// Useful for FPS and regression tests. Not used by the debugger because traps // Useful for FPS and regression tests. Not used by the debugger because traps
// (and volatile traps) are more flexible. // (and volatile traps) are more flexible.
func (vcs *VCS) RunForFrameCount(numFrames int, continueCheck func(frame int) (emulation.State, error)) error { func (vcs *VCS) RunForFrameCount(numFrames int, continueCheck func(frame int) (govern.State, error)) error {
if continueCheck == nil { if continueCheck == nil {
continueCheck = func(frame int) (emulation.State, error) { return emulation.Running, nil } continueCheck = func(frame int) (govern.State, error) { return govern.Running, nil }
} }
frameNum := vcs.TV.GetCoords().Frame frameNum := vcs.TV.GetCoords().Frame
targetFrame := frameNum + numFrames targetFrame := frameNum + numFrames
state := emulation.Running state := govern.Running
for frameNum != targetFrame && state != emulation.Ending { for frameNum != targetFrame && state != govern.Ending {
err := vcs.Step(nil) err := vcs.Step(nil)
if err != nil { if err != nil {
return err return err

View file

@ -20,7 +20,7 @@ import (
"strings" "strings"
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/hardware/television/coords" "github.com/jetsetilly/gopher2600/hardware/television/coords"
"github.com/jetsetilly/gopher2600/hardware/television/signal" "github.com/jetsetilly/gopher2600/hardware/television/signal"
"github.com/jetsetilly/gopher2600/hardware/television/specification" "github.com/jetsetilly/gopher2600/hardware/television/specification"
@ -174,7 +174,7 @@ type Television struct {
prevSignalFirst int prevSignalFirst int
// state of emulation // state of emulation
emulationState emulation.State emulationState govern.State
} }
// NewTelevision creates a new instance of the television type, satisfying the // NewTelevision creates a new instance of the television type, satisfying the
@ -535,7 +535,7 @@ func (tv *Television) newScanline() error {
// check for realtime mixing requirements. if it is required then // check for realtime mixing requirements. if it is required then
// immediately push the audio data from the previous frame to the mixer // immediately push the audio data from the previous frame to the mixer
if tv.realtimeMixer != nil && tv.emulationState == emulation.Running && tv.state.frameInfo.Stable { if tv.realtimeMixer != nil && tv.emulationState == govern.Running && tv.state.frameInfo.Stable {
if tv.realtimeMixer.MoreAudio() { if tv.realtimeMixer.MoreAudio() {
err := tv.realtimeMixer.SetAudio(tv.prevSignals[:tv.prevSignalLastIdx]) err := tv.realtimeMixer.SetAudio(tv.prevSignals[:tv.prevSignalLastIdx])
if err != nil { if err != nil {
@ -669,7 +669,7 @@ func (tv *Television) newFrame(fromVsync bool) error {
// renderers and audio mixers. // renderers and audio mixers.
func (tv *Television) renderSignals() error { func (tv *Television) renderSignals() error {
// do not render pixels if emulation is in the rewinding state // do not render pixels if emulation is in the rewinding state
if tv.emulationState != emulation.Rewinding { if tv.emulationState != govern.Rewinding {
for _, r := range tv.renderers { for _, r := range tv.renderers {
err := r.SetPixels(tv.signals, tv.currentSignalIdx) err := r.SetPixels(tv.signals, tv.currentSignalIdx)
if err != nil { if err != nil {
@ -768,23 +768,23 @@ func (tv *Television) SetSpec(spec string) error {
// SetEmulationState is called by emulation whenever state changes. How we // SetEmulationState is called by emulation whenever state changes. How we
// handle incoming signals depends on the current state. // handle incoming signals depends on the current state.
func (tv *Television) SetEmulationState(state emulation.State) error { func (tv *Television) SetEmulationState(state govern.State) error {
prev := tv.emulationState prev := tv.emulationState
tv.emulationState = state tv.emulationState = state
switch prev { switch prev {
case emulation.Paused: case govern.Paused:
// start off the unpaused state by measuring the current framerate. // start off the unpaused state by measuring the current framerate.
// this "clears" the ticker channel and means the feedback from // this "clears" the ticker channel and means the feedback from
// GetActualFPS() is less misleading // GetActualFPS() is less misleading
tv.lmtr.measureActual() tv.lmtr.measureActual()
case emulation.Rewinding: case govern.Rewinding:
tv.renderSignals() tv.renderSignals()
} }
switch state { switch state {
case emulation.Paused: case govern.Paused:
err := tv.renderSignals() err := tv.renderSignals()
if err != nil { if err != nil {
return err return err

View file

@ -22,11 +22,10 @@ import (
"github.com/jetsetilly/gopher2600/cartridgeloader" "github.com/jetsetilly/gopher2600/cartridgeloader"
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/hardware" "github.com/jetsetilly/gopher2600/hardware"
"github.com/jetsetilly/gopher2600/hardware/television" "github.com/jetsetilly/gopher2600/hardware/television"
"github.com/jetsetilly/gopher2600/setup" "github.com/jetsetilly/gopher2600/setup"
"github.com/jetsetilly/gopher2600/userinput"
) )
// sentinal error returned by Run() loop. // sentinal error returned by Run() loop.
@ -100,7 +99,7 @@ func Check(output io.Writer, profile Profile, cartload cartridgeloader.Loader, s
performanceBrake := 0 performanceBrake := 0
// run until specified time elapses // run until specified time elapses
err = vcs.Run(func() (emulation.State, error) { err = vcs.Run(func() (govern.State, error) {
for { for {
performanceBrake++ performanceBrake++
if performanceBrake >= hardware.PerformanceBrake { if performanceBrake >= hardware.PerformanceBrake {
@ -112,7 +111,7 @@ func Check(output io.Writer, profile Profile, cartload cartridgeloader.Loader, s
// period has finished, return false to cause vcs.Run() to // period has finished, return false to cause vcs.Run() to
// return // return
if v { if v {
return emulation.Ending, curated.Errorf(timedOut) return govern.Ending, curated.Errorf(timedOut)
} }
// timerChan has returned false which indicates that the // timerChan has returned false which indicates that the
@ -121,11 +120,11 @@ func Check(output io.Writer, profile Profile, cartload cartridgeloader.Loader, s
// frame. // frame.
startFrame = tv.GetCoords().Frame startFrame = tv.GetCoords().Frame
default: default:
return emulation.Running, nil return govern.Running, nil
} }
} }
return emulation.Running, nil return govern.Running, nil
} }
}) })
return err return err
@ -148,38 +147,3 @@ func Check(output io.Writer, profile Profile, cartload cartridgeloader.Loader, s
return nil return nil
} }
// stubEmulation is handed to the GUI through ReqSetEmulation. Provides the
// minimum implementation for the Emulation interface.
type stubEmulation struct {
vcs emulation.VCS
tv emulation.TV
}
func (e *stubEmulation) TV() emulation.TV {
return e.tv
}
func (e *stubEmulation) VCS() emulation.VCS {
return e.vcs
}
func (e *stubEmulation) Debugger() emulation.Debugger {
return nil
}
func (e *stubEmulation) UserInput() chan userinput.Event {
return nil
}
func (e *stubEmulation) SetFeature(request emulation.FeatureReq, args ...emulation.FeatureReqData) error {
return nil
}
func (e *stubEmulation) State() emulation.State {
return emulation.Running
}
func (e *stubEmulation) Mode() emulation.Mode {
return emulation.ModePlay
}

View file

@ -17,7 +17,7 @@ package reflection
import ( import (
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/hardware" "github.com/jetsetilly/gopher2600/hardware"
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper" "github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper"
"github.com/jetsetilly/gopher2600/hardware/television" "github.com/jetsetilly/gopher2600/hardware/television"
@ -30,7 +30,7 @@ import (
type Reflector struct { type Reflector struct {
vcs *hardware.VCS vcs *hardware.VCS
renderer Renderer renderer Renderer
emulationState emulation.State emulationState govern.State
history []ReflectedVideoStep history []ReflectedVideoStep
@ -57,17 +57,17 @@ func (ref *Reflector) Clear() {
// SetEmulationState is called by emulation whenever state changes. How we // SetEmulationState is called by emulation whenever state changes. How we
// handle reflections depends on the current state. // handle reflections depends on the current state.
func (ref *Reflector) SetEmulationState(state emulation.State) { func (ref *Reflector) SetEmulationState(state govern.State) {
prev := ref.emulationState prev := ref.emulationState
ref.emulationState = state ref.emulationState = state
switch prev { switch prev {
case emulation.Rewinding: case govern.Rewinding:
ref.render() ref.render()
} }
switch state { switch state {
case emulation.Paused: case govern.Paused:
err := ref.render() err := ref.render()
if err != nil { if err != nil {
logger.Logf("reflection", "%v", err) logger.Logf("reflection", "%v", err)
@ -125,7 +125,7 @@ func (ref *Reflector) Step(bank mapper.BankInfo) error {
// push history to reflection renderer // push history to reflection renderer
func (ref *Reflector) render() error { func (ref *Reflector) render() error {
if ref.emulationState != emulation.Rewinding { if ref.emulationState != govern.Rewinding {
if ref.renderer != nil { if ref.renderer != nil {
if err := ref.renderer.Reflect(ref.history); err != nil { if err := ref.renderer.Reflect(ref.history); err != nil {
return curated.Errorf("reflection: %v", err) return curated.Errorf("reflection: %v", err)

View file

@ -26,7 +26,7 @@ import (
"github.com/jetsetilly/gopher2600/cartridgeloader" "github.com/jetsetilly/gopher2600/cartridgeloader"
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/database" "github.com/jetsetilly/gopher2600/database"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/hardware" "github.com/jetsetilly/gopher2600/hardware"
"github.com/jetsetilly/gopher2600/hardware/television" "github.com/jetsetilly/gopher2600/hardware/television"
"github.com/jetsetilly/gopher2600/logger" "github.com/jetsetilly/gopher2600/logger"
@ -160,7 +160,7 @@ func (reg *LogRegression) regress(newRegression bool, output io.Writer, msg stri
logOutput := &strings.Builder{} logOutput := &strings.Builder{}
// run emulation // run emulation
err = vcs.RunForFrameCount(reg.NumFrames, func(frame int) (emulation.State, error) { err = vcs.RunForFrameCount(reg.NumFrames, func(frame int) (govern.State, error) {
// display progress meter every 1 second // display progress meter every 1 second
select { select {
case <-tck.C: case <-tck.C:
@ -170,7 +170,7 @@ func (reg *LogRegression) regress(newRegression bool, output io.Writer, msg stri
logger.WriteRecent(logOutput) logger.WriteRecent(logOutput)
return emulation.Running, nil return govern.Running, nil
}) })
if err != nil { if err != nil {

View file

@ -25,8 +25,8 @@ import (
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/database" "github.com/jetsetilly/gopher2600/database"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/digest" "github.com/jetsetilly/gopher2600/digest"
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/hardware" "github.com/jetsetilly/gopher2600/hardware"
"github.com/jetsetilly/gopher2600/hardware/riot/ports" "github.com/jetsetilly/gopher2600/hardware/riot/ports"
"github.com/jetsetilly/gopher2600/hardware/television" "github.com/jetsetilly/gopher2600/hardware/television"
@ -150,13 +150,13 @@ func (reg *PlaybackRegression) regress(newRegression bool, output io.Writer, msg
tck := time.NewTicker(dur) tck := time.NewTicker(dur)
// run emulation // run emulation
err = vcs.Run(func() (emulation.State, error) { err = vcs.Run(func() (govern.State, error) {
hasEnded, err := plb.EndFrame() hasEnded, err := plb.EndFrame()
if err != nil { if err != nil {
return emulation.Ending, curated.Errorf("playback: %v", err) return govern.Ending, curated.Errorf("playback: %v", err)
} }
if hasEnded { if hasEnded {
return emulation.Ending, curated.Errorf("playback: ended unexpectedly") return govern.Ending, curated.Errorf("playback: ended unexpectedly")
} }
// display progress meter every 1 second // display progress meter every 1 second
@ -165,7 +165,7 @@ func (reg *PlaybackRegression) regress(newRegression bool, output io.Writer, msg
output.Write([]byte(fmt.Sprintf("\r%s [%s]", msg, plb))) output.Write([]byte(fmt.Sprintf("\r%s [%s]", msg, plb)))
default: default:
} }
return emulation.Running, nil return govern.Running, nil
}) })
if err != nil { if err != nil {

View file

@ -27,8 +27,8 @@ import (
"github.com/jetsetilly/gopher2600/cartridgeloader" "github.com/jetsetilly/gopher2600/cartridgeloader"
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/database" "github.com/jetsetilly/gopher2600/database"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/digest" "github.com/jetsetilly/gopher2600/digest"
"github.com/jetsetilly/gopher2600/emulation"
"github.com/jetsetilly/gopher2600/hardware" "github.com/jetsetilly/gopher2600/hardware"
"github.com/jetsetilly/gopher2600/hardware/television" "github.com/jetsetilly/gopher2600/hardware/television"
"github.com/jetsetilly/gopher2600/setup" "github.com/jetsetilly/gopher2600/setup"
@ -232,7 +232,7 @@ func (reg *VideoRegression) regress(newRegression bool, output io.Writer, msg st
tck := time.NewTicker(dur) tck := time.NewTicker(dur)
// run emulation // run emulation
err = vcs.RunForFrameCount(reg.NumFrames, func(frame int) (emulation.State, error) { err = vcs.RunForFrameCount(reg.NumFrames, func(frame int) (govern.State, error) {
// display progress meter every 1 second // display progress meter every 1 second
select { select {
case <-tck.C: case <-tck.C:
@ -259,7 +259,7 @@ func (reg *VideoRegression) regress(newRegression bool, output io.Writer, msg st
} }
} }
return emulation.Running, nil return govern.Running, nil
}) })
if err != nil { if err != nil {

View file

@ -20,7 +20,7 @@ import (
"strings" "strings"
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/hardware" "github.com/jetsetilly/gopher2600/hardware"
"github.com/jetsetilly/gopher2600/hardware/cpu" "github.com/jetsetilly/gopher2600/hardware/cpu"
"github.com/jetsetilly/gopher2600/hardware/memory" "github.com/jetsetilly/gopher2600/hardware/memory"
@ -32,6 +32,13 @@ import (
"github.com/jetsetilly/gopher2600/logger" "github.com/jetsetilly/gopher2600/logger"
) )
// Emulation defines as much of the emulation we require access to.
type Emulation interface {
Mode() govern.Mode
State() govern.State
VCS() *hardware.VCS
}
// Runner provides the rewind package the opportunity to run the emulation. // Runner provides the rewind package the opportunity to run the emulation.
type Runner interface { type Runner interface {
// CatchupLoop should loop until the frame/scanline/clock coordinates are // CatchupLoop should loop until the frame/scanline/clock coordinates are
@ -106,7 +113,7 @@ const overhead = 2
// Rewind contains a history of machine states for the emulation. // Rewind contains a history of machine states for the emulation.
type Rewind struct { type Rewind struct {
emulation emulation.Emulation emulation Emulation
vcs *hardware.VCS vcs *hardware.VCS
runner Runner runner Runner
@ -145,10 +152,10 @@ type Rewind struct {
} }
// NewRewind is the preferred method of initialisation for the Rewind type. // NewRewind is the preferred method of initialisation for the Rewind type.
func NewRewind(emulation emulation.Emulation, runner Runner) (*Rewind, error) { func NewRewind(emulation Emulation, runner Runner) (*Rewind, error) {
r := &Rewind{ r := &Rewind{
emulation: emulation, emulation: emulation,
vcs: emulation.VCS().(*hardware.VCS), vcs: emulation.VCS(),
runner: runner, runner: runner,
} }
@ -443,7 +450,7 @@ type findResults struct {
// the one that is requested. // the one that is requested.
func (r *Rewind) findFrameIndex(frame int) findResults { func (r *Rewind) findFrameIndex(frame int) findResults {
searchFrame := frame - 1 searchFrame := frame - 1
if r.emulation.Mode() == emulation.ModeDebugger { if r.emulation.Mode() == govern.ModeDebugger {
searchFrame-- searchFrame--
} }

View file

@ -17,7 +17,7 @@ package rewind
import ( import (
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/hardware/television" "github.com/jetsetilly/gopher2600/hardware/television"
"github.com/jetsetilly/gopher2600/hardware/television/specification" "github.com/jetsetilly/gopher2600/hardware/television/specification"
) )
@ -160,7 +160,7 @@ func (r *Rewind) GetTimeline() Timeline {
func (r *Rewind) addTimelineEntry(frameInfo television.FrameInfo) { func (r *Rewind) addTimelineEntry(frameInfo television.FrameInfo) {
// do not alter the timeline information if we're in the rewinding state // do not alter the timeline information if we're in the rewinding state
if r.emulation.State() == emulation.Rewinding { if r.emulation.State() == govern.Rewinding {
return return
} }

View file

@ -24,7 +24,7 @@ import (
"github.com/jetsetilly/gopher2600/cartridgeloader" "github.com/jetsetilly/gopher2600/cartridgeloader"
"github.com/jetsetilly/gopher2600/curated" "github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/hardware" "github.com/jetsetilly/gopher2600/hardware"
"github.com/jetsetilly/gopher2600/hardware/instance" "github.com/jetsetilly/gopher2600/hardware/instance"
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper" "github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper"
@ -193,17 +193,17 @@ func (thmb *Thumbnailer) CreateFromLoader(cartload cartridgeloader.Loader, numFr
tgtFrame := thmb.vcs.TV.GetCoords().Frame + numFrames tgtFrame := thmb.vcs.TV.GetCoords().Frame + numFrames
err = thmb.vcs.Run(func() (emulation.State, error) { err = thmb.vcs.Run(func() (govern.State, error) {
select { select {
case <-thmb.emulationQuit: case <-thmb.emulationQuit:
return emulation.Ending, nil return govern.Ending, nil
default: default:
} }
if numFrames != UndefinedNumFrames && thmb.vcs.TV.GetCoords().Frame >= tgtFrame { if numFrames != UndefinedNumFrames && thmb.vcs.TV.GetCoords().Frame >= tgtFrame {
return emulation.Ending, nil return govern.Ending, nil
} }
return emulation.Running, nil return govern.Running, nil
}) })
if err != nil { if err != nil {
logger.Logf("thumbnailer", err.Error()) logger.Logf("thumbnailer", err.Error())
@ -235,17 +235,17 @@ func (thmb *Thumbnailer) SingleFrameFromRewindState(state *rewind.State) {
// run until target frame has been generated // run until target frame has been generated
tgtFrame := thmb.vcs.TV.GetCoords().Frame + 1 tgtFrame := thmb.vcs.TV.GetCoords().Frame + 1
err := thmb.vcs.Run(func() (emulation.State, error) { err := thmb.vcs.Run(func() (govern.State, error) {
select { select {
case <-thmb.emulationQuit: case <-thmb.emulationQuit:
return emulation.Ending, nil return govern.Ending, nil
default: default:
} }
if thmb.vcs.TV.GetCoords().Frame >= tgtFrame { if thmb.vcs.TV.GetCoords().Frame >= tgtFrame {
return emulation.Ending, nil return govern.Ending, nil
} }
return emulation.Running, nil return govern.Running, nil
}) })
if err != nil { if err != nil {

View file

@ -16,12 +16,18 @@
package tracker package tracker
import ( import (
"github.com/jetsetilly/gopher2600/emulation" "github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/hardware/television" "github.com/jetsetilly/gopher2600/hardware/television"
"github.com/jetsetilly/gopher2600/hardware/television/coords" "github.com/jetsetilly/gopher2600/hardware/television/coords"
"github.com/jetsetilly/gopher2600/hardware/tia/audio" "github.com/jetsetilly/gopher2600/hardware/tia/audio"
) )
// Emulation defines as much of the emulation we require access to.
type Emulation interface {
State() govern.State
TV() *television.Television
}
type Entry struct { type Entry struct {
Coords coords.TelevisionCoords Coords coords.TelevisionCoords
Channel int Channel int
@ -35,7 +41,7 @@ type Entry struct {
// Tracker implements the audio.Tracker interface and keeps a history of the // Tracker implements the audio.Tracker interface and keeps a history of the
// audio registers over time. // audio registers over time.
type Tracker struct { type Tracker struct {
emulation emulation.Emulation emulation Emulation
entries []Entry entries []Entry
@ -49,7 +55,7 @@ type Tracker struct {
const maxTrackerEntries = 1024 const maxTrackerEntries = 1024
// NewTracker is the preferred method of initialisation for the Tracker type. // NewTracker is the preferred method of initialisation for the Tracker type.
func NewTracker(emulation emulation.Emulation) *Tracker { func NewTracker(emulation Emulation) *Tracker {
return &Tracker{ return &Tracker{
emulation: emulation, emulation: emulation,
entries: make([]Entry, 0, maxTrackerEntries), entries: make([]Entry, 0, maxTrackerEntries),
@ -63,7 +69,7 @@ func (tr *Tracker) Reset() {
// Tick implements the audio.Tracker interface // Tick implements the audio.Tracker interface
func (tr *Tracker) Tick(channel int, reg audio.Registers) { func (tr *Tracker) Tick(channel int, reg audio.Registers) {
if tr.emulation.State() == emulation.Rewinding { if tr.emulation.State() == govern.Rewinding {
return return
} }
@ -71,7 +77,7 @@ func (tr *Tracker) Tick(channel int, reg audio.Registers) {
tr.prevRegister[channel] = reg tr.prevRegister[channel] = reg
if changed { if changed {
tv := tr.emulation.TV().(*television.Television) tv := tr.emulation.TV()
e := Entry{ e := Entry{
Coords: tv.GetCoords(), Coords: tv.GetCoords(),