lazyvalues

package
v0.7.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 28, 2020 License: GPL-3.0, GPL-3.0 Imports: 15 Imported by: 0

Documentation

Overview

Package lazyvalues is the method used by sdlimgui to read emulator data from the GUI thread. Reading emulator values (which are handled by the emulator thread) will cause race errors in almost every circumstance so it is important that this lazyvalue mechanism be used whenever emulator information is required.

Note that this system is used in addition to the other systems which hand off information to the GUI. The PixelRenderer and AudioMixer interfaces from the television packages should be used in the normal way.

For writing data back to the emulation thread the terminal interface can be used for many things. Alternatively the debugger.PushRawEvent() function can be used. There is currently no way of pushing events onto the emulator unless the debugging loop is in use.

Example -------

Retrieving the foreground color of the playfield:

col := lazyval.Playfield.ForegroundColor

Writing the playfield values is done thought debugger's "raw event" system:

lazyval.Dbg.PushRawEvent(func() {
	lazyval.VCS.TIA.Video.Playfield.ForegroundColor = col
})

Implementation --------------

The main goal of the lazyvalues system is to prevent the GUI loop from locking up while waiting for a response from the emulator thread. Given that we must use a thred-sage a communication channel between the GUI and emulator threads to avoid race conditions this is important - a unresponsive GUI can needlessly damage the user experience.

This section outlines the principles of the internals of the lazyvalues package. Users of the package need not understand these points.

The principle of the lazyvalues system is to use whatever values are available immediately and to update those values "lazily". In a GUI context this means that the values seen on screen may be several frames behind the emulation but at normal GUI refresh rates this isn't noticeable. Cartainly, when the emulation is paused, the values seen in the GUI will be accurate.

Lazy values are updated with the Refresh() function. In turn, this function will call the push() and update() functions of each component in the lazyvalues package.

The pseudocode below shows how the Refresh() updates the values in every type in the lazyvalues system, at the same time as requesting new values.

	func Refresh() {                        .------------------.
		debugger.PushRawEvent()   ----->	| CPU.push()       |
											| RAM.push()       |
     CPU.update()						| Playfield.push() |
		RAM.update()						|   .              |
			.								|   .              |
			.								|   .              |
			.								| Log.push()       |
		Log.update()						 ------------------
	}

The update() and push() functions (not visible from outside the lazyvalues package) of each type handle the retreiving and updating of emulation values. In most instances, this is achieved with the atomic.Value type, from the atomic package in the Go standard library.

In the instance of the LazyController type, we cannot use the atomic.Value. This is because of the limitation on atomic.Values only being able to store consistently typed values. In the case of the LazyController type we need to store the ports.Peripheral interface, which by definition may have differing underlying types.

For this reason, the LazyController type uses channels to communicate between the push() function (ie. the emulation thread) and the update() function, rather than atomic values. We could of course, use channels for all types and do away with atomic values but it is felt that in most cases the atomic solution is clearer.

As a final point about atomic values, note that arrays of atomic values require that the array itself be an atomic value, as well as the elements of the array. For example, the RAM package has code equivalent to this; an array of atomic.Value stored as an atomic value:

	 var ram atomic.Value
  ram.Store(make([]atomic.Value, size)

The exception to all the rules is the LazyBreakpoints type. Like LazyRAM it employs an array of atomic.Values storied as an atomic Value but unlike everythin else it is not refreshed with update() and push(). Instead, the unique function HasBreak() is used, which is called by the Disassembly window for every cartridge entry that is visible.

The reason for this function is so that we can pass an instance of disassembly.Entry and probe the debugger's breakpoints with that. There may be other ways of achieving the same effect, but whatever way we do it the additional context provided by the disassembly.Entry is required.

Ensuring Up-To-Date Information -------------------------------

Sometimes the GUI wants up-to-date information and nothing else will do. This is particularly important when the GUI is interacting directly with the emulation. For example, the rewind slider can stutter between the moment of selection/release and the the moment when the emulation has caught-up with the request.

In these instances, the lazy type can be instructed to "wait" for up-to-date values. Currently only the LazyRewind type supports this and can accessed by setting the Wait flag to true.

Use of "wait" should be kept to a minimum to ensure system responsiveness.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type LazyBall

type LazyBall struct {

	// Bs is a pointer to the "live" data in the other thread. Do not access
	// the fields in this struct directly. It can be used in PushRawEvent()
	// call
	Bs *video.BallSprite

	ResetPixel    int
	HmovedPixel   int
	Color         uint8
	VerticalDelay bool
	EnabledDelay  bool
	Enabled       bool
	Ctrlpf        uint8
	Size          uint8
	Hmove         uint8
	MoreHmove     bool

	EncActive     bool
	EncSecondHalf bool
	EncCpy        int
	EncTicks      int
	// contains filtered or unexported fields
}

LazyBall lazily accesses ball information from the emulator.

type LazyBreakpoints added in v0.7.1

type LazyBreakpoints struct {
	// contains filtered or unexported fields
}

func (*LazyBreakpoints) HasBreak added in v0.7.1

HasBreak checks to see if disassembly entry has a breakpoint.

type LazyCPU

type LazyCPU struct {
	HasReset  bool
	RdyFlg    bool
	PC        registers.ProgramCounter
	A         registers.Register
	X         registers.Register
	Y         registers.Register
	SP        registers.Register
	StatusReg registers.StatusRegister
	// contains filtered or unexported fields
}

LazyCPU lazily accesses CPU information from the emulator.

type LazyCart

type LazyCart struct {
	ID       string
	Summary  string
	Filename string
	NumBanks int
	CurrBank mapper.BankInfo

	HasStaticBus bool
	StaticBus    mapper.CartStaticBus
	Static       []mapper.CartStatic

	HasRegistersBus bool
	RegistersBus    mapper.CartRegistersBus
	Registers       mapper.CartRegisters

	HasRAMbus bool
	RAMbus    mapper.CartRAMbus
	RAM       []mapper.CartRAM

	HasTapeBus bool
	TapeBus    mapper.CartTapeBus
	TapeState  mapper.CartTapeState

	IsPlusROM       bool
	PlusROMAddrInfo plusrom.AddrInfo
	PlusROMNick     string
	PlusROMID       string
	PlusROMRecvBuff []uint8
	PlusROMSendBuff []uint8
	// contains filtered or unexported fields
}

LazyCart lazily accesses cartridge information from the emulator.

type LazyChipRegisters added in v0.7.1

type LazyChipRegisters struct {
	SWCHA  uint8
	SWACNT uint8
	SWCHB  uint8
	INPT0  uint8
	INPT1  uint8
	INPT2  uint8
	INPT3  uint8
	INPT4  uint8
	INPT5  uint8
	// contains filtered or unexported fields
}

LazyChipRegisters lazily accesses chip registere information from the emulator.

type LazyCollisions added in v0.2.1

type LazyCollisions struct {
	CXM0P  uint8
	CXM1P  uint8
	CXP0FB uint8
	CXP1FB uint8
	CXM0FB uint8
	CXM1FB uint8
	CXBLPF uint8
	CXPPMM uint8
	// contains filtered or unexported fields
}

LazyTimer lazily accesses RIOT timer information from the emulator.

type LazyControllers

type LazyControllers struct {
	Player0 ports.Peripheral
	Player1 ports.Peripheral
	// contains filtered or unexported fields
}

LazyControllers lazily accesses controller information from the emulator.

type LazyDebugger

type LazyDebugger struct {
	Quantum    debugger.QuantumMode
	LastResult disassembly.Entry
	// contains filtered or unexported fields
}

LazyDebugger lazily accesses Debugger information.

type LazyLog added in v0.7.1

type LazyLog struct {
	Log   []logger.Entry
	Dirty bool
	// contains filtered or unexported fields
}

LazyLog lazily accesses chip registere information from the emulator.

type LazyMissile

type LazyMissile struct {
	Ms            *video.MissileSprite
	ResetPixel    int
	HmovedPixel   int
	Color         uint8
	Enabled       bool
	Nusiz         uint8
	Size          uint8
	Copies        uint8
	Hmove         uint8
	MoreHmove     bool
	ResetToPlayer bool

	EncActive     bool
	EncSecondHalf bool
	EncCpy        int
	EncTicks      int
	// contains filtered or unexported fields
}

LazyMissile lazily accesses missile information from the emulator.

type LazyPlayer

type LazyPlayer struct {

	// P is a pointer to the "live" data in the other thread. Do not access
	// the fields in this struct directly. It can be used in PushRawEvent()
	// call
	Ps *video.PlayerSprite

	ResetPixel    int
	HmovedPixel   int
	Color         uint8
	Nusiz         uint8
	SizeAndCopies uint8
	Reflected     bool
	VerticalDelay bool
	Hmove         uint8
	MoreHmove     bool
	GfxDataNew    uint8
	GfxDataOld    uint8

	ScanIsActive             bool
	ScanIsLatching           bool
	ScanPixel                int
	ScanCpy                  int
	ScanLatchedSizeAndCopies uint8
	// contains filtered or unexported fields
}

LazyPlayer lazily accesses player information from the emulator.

type LazyPlayfield

type LazyPlayfield struct {

	// Pf is a pointer to the "live" data in the other thread. Do not access
	// the fields in this struct directly. It can be used in PushRawEvent()
	// call
	Pf *video.Playfield

	Ctrlpf          uint8
	ForegroundColor uint8
	BackgroundColor uint8
	Reflected       bool
	Scoremode       bool
	Priority        bool
	Region          video.ScreenRegion
	PF0             uint8
	PF1             uint8
	PF2             uint8
	Idx             int
	LeftData        []bool
	RightData       []bool
	// contains filtered or unexported fields
}

LazyPlayfield lazily accesses playfield information from the emulator.

type LazyPrefs added in v0.2.1

type LazyPrefs struct {
	RandomState      bool
	RandomPins       bool
	FxxxMirror       bool
	Symbols          bool
	RewindMaxEntries int
	RewindFreq       int
	// contains filtered or unexported fields
}

LazyPrefs lazily accesses the debugger/emulator's preference states.

type LazyRAM added in v0.2.1

type LazyRAM struct {
	RAM []uint8
	// contains filtered or unexported fields
}

LazyRAM lazily accesses the RAM area of VCS memory.

type LazyRewind added in v0.7.1

type LazyRewind struct {
	Summary    rewind.Summary
	Comparison *rewind.State
	// contains filtered or unexported fields
}

LazyRewind lazily accesses VCS rewind information.

type LazySaveKey added in v0.7.1

type LazySaveKey struct {
	SaveKeyActive bool

	SDA        []float32
	SCL        []float32
	State      savekey.MessageState
	Dir        savekey.DataDirection
	Ack        bool
	Bits       uint8
	BitsCt     int
	Address    uint16
	EEPROMdata []uint8
	Dirty      bool
	// contains filtered or unexported fields
}

LazyChipRegisters lazily accesses chip registere information from the emulator.

type LazyTV

type LazyTV struct {
	Spec       specification.Spec
	TVstr      string
	LastSignal signal.SignalAttributes
	Frame      int
	Scanline   int
	HP         int
	IsStable   bool
	AcutalFPS  float32
	ReqFPS     float32
	// contains filtered or unexported fields
}

LazyTV lazily accesses tv information from the emulator.

type LazyTimer

type LazyTimer struct {
	Divider        string
	INTIMvalue     uint8
	TicksRemaining int
	// contains filtered or unexported fields
}

LazyTimer lazily accesses RIOT timer information from the emulator.

type LazyValues added in v0.7.1

type LazyValues struct {

	// the debugger is racy. it should not be accessed directly except through
	// the lazy system or directly with Debugger.PushRawEvent()
	Dbg *debugger.Debugger

	// pointers to these instances. non-pointer instances trigger the race
	// detector for some reason.
	Debugger      *LazyDebugger
	CPU           *LazyCPU
	RAM           *LazyRAM
	Timer         *LazyTimer
	Playfield     *LazyPlayfield
	Player0       *LazyPlayer
	Player1       *LazyPlayer
	Missile0      *LazyMissile
	Missile1      *LazyMissile
	Ball          *LazyBall
	TV            *LazyTV
	Cart          *LazyCart
	Controllers   *LazyControllers
	Prefs         *LazyPrefs
	Collisions    *LazyCollisions
	ChipRegisters *LazyChipRegisters
	Log           *LazyLog
	SaveKey       *LazySaveKey
	Rewind        *LazyRewind

	// note that LazyBreakpoints works slightly different to the the other Lazy* types.
	Breakpoints *LazyBreakpoints
	// contains filtered or unexported fields
}

LazyValues contains all values required by a debugger running in a different thread to the emulation. Use these values rather than directly accessing those exposed by the emulation.

func NewLazyValues added in v0.7.1

func NewLazyValues() *LazyValues

NewLazyValues is the preferred method of initialisation for the Values type.

func (*LazyValues) Refresh added in v0.7.1

func (val *LazyValues) Refresh()

Refresh lazy values.

func (*LazyValues) Reset added in v0.7.1

func (val *LazyValues) Reset(changingCart bool)

Reset lazy values instance.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL