lazyvalues

package
v0.24.2 Latest Latest
Warning

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

Go to latest
Published: Jun 30, 2023 License: GPL-3.0, GPL-3.0 Imports: 21 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.PushFunction() 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.PushFunction(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.PushFunction()   ----->	| 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 a PushFunction()
	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 LazyBus added in v0.20.0

type LazyBus struct {
	AddressBus    uint16
	DataBus       uint8
	LastCPUWrite  bool
	DataBusDriven uint8
	// contains filtered or unexported fields
}

LazyBus lazily accesses Mem information from the emulator.

type LazyCPU

type LazyCPU struct {
	HasReset           bool
	RdyFlg             bool
	Killed             bool
	PC                 registers.ProgramCounter
	A                  registers.Register
	X                  registers.Register
	Y                  registers.Register
	SP                 registers.StackPointer
	StatusReg          registers.StatusRegister
	LastResult         execution.Result
	RTSPrediction      uint16
	RTSPredictionValid bool
	// contains filtered or unexported fields
}

LazyCPU lazily accesses CPU information from the emulator.

type LazyCart

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

	HasStaticBus bool
	StaticBus    mapper.CartStaticBus
	Static       mapper.CartStatic

	HasRegistersBus bool
	Registers       mapper.CartRegisters

	HasRAMbus bool
	RAM       []mapper.CartRAM

	HasTapeBus bool
	TapeState  mapper.CartTapeState

	HasCoProcBus bool
	CoProcID     string
	CoProcPC     uint32

	IsPlusROM        bool
	PlusROMAddrInfo  plusrom.AddrInfo
	PlusROMSendState plusrom.SendState
	// contains filtered or unexported fields
}

LazyCart lazily accesses cartridge 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 LazyDebugger

type LazyDebugger struct {
	Quantum         debugger.Quantum
	LiveDisasmEntry disassembly.Entry
	Breakpoints     debugger.LazyBreakpointsQuery
	HasChanged      bool

	// 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
	// govern.State() value (which is safe to obtain outside of the lazy
	// system) when synchronisation is important
	State govern.State
	// contains filtered or unexported fields
}

LazyDebugger lazily accesses Debugger information.

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 LazyPeripherals added in v0.16.0

type LazyPeripherals struct {
	LeftPlayer  ports.Peripheral
	RightPlayer ports.Peripheral
	// contains filtered or unexported fields
}

LazyPeripherals lazily accesses controller information from the emulator.

type LazyPhaseClock added in v0.16.0

type LazyPhaseClock struct {
	LastPClk phaseclock.PhaseClock
	// contains filtered or unexported fields
}

LazyPhaseClock lazily accesses PhaseClock 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 a PushFunction()
	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 a PushFuncion()
	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 LazyPorts added in v0.16.0

type LazyPorts struct {
	SWCHA         uint8
	SWACNT        uint8
	SWCHA_W       uint8
	SWCHA_Derived uint8
	SWCHB         uint8
	SWBCNT        uint8
	SWCHB_W       uint8
	SWCHB_Derived uint8
	INPT0         uint8
	INPT1         uint8
	INPT2         uint8
	INPT3         uint8
	INPT4         uint8
	INPT5         uint8
	// contains filtered or unexported fields
}

LazyPorts lazily accesses RIOT Ports information from the emulator.

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 {
	Timeline   rewind.Timeline
	Comparison rewind.ComparisonState
	// 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.SaveKeyState
	Dir            savekey.DataDirection
	Ack            bool
	Bits           uint8
	BitsCt         int
	Address        uint16
	EEPROMdata     []uint8
	EEPROMdiskData []uint8
	// contains filtered or unexported fields
}

LazyChipRegisters lazily accesses chip registere information from the emulator.

type LazyTV

type LazyTV struct {
	FrameInfo  television.FrameInfo
	TVstr      string
	LastSignal signal.SignalAttributes
	Coords     coords.TelevisionCoords
	Hz         float32
	ActualFPS  float32
	ReqFPS     float32
	// contains filtered or unexported fields
}

LazyTV lazily accesses tv information from the emulator.

type LazyTimer

type LazyTimer struct {
	Divider        timer.Divider
	INTIM          uint8
	TicksRemaining int
	TIMINT         uint8
	// contains filtered or unexported fields
}

LazyTimer lazily accesses RIOT timer information from the emulator.

type LazyValues added in v0.7.1

type LazyValues struct {

	// pointers to these instances. non-pointer instances trigger the race
	// detector for some reason.
	Debugger    *LazyDebugger
	CPU         *LazyCPU
	Bus         *LazyBus
	Phaseclock  *LazyPhaseClock
	RAM         *LazyRAM
	Timer       *LazyTimer
	Playfield   *LazyPlayfield
	Player0     *LazyPlayer
	Player1     *LazyPlayer
	Missile0    *LazyMissile
	Missile1    *LazyMissile
	Ball        *LazyBall
	TV          *LazyTV
	Cart        *LazyCart
	Peripherals *LazyPeripherals
	Collisions  *LazyCollisions
	Ports       *LazyPorts
	SaveKey     *LazySaveKey
	Rewind      *LazyRewind
	// 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(dbg *debugger.Debugger) *LazyValues

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

func (*LazyValues) FastRefresh added in v0.15.0

func (val *LazyValues) FastRefresh()

FastRefresh lazy values. Updates only the values that are needed in playmode.

func (*LazyValues) Refresh added in v0.7.1

func (val *LazyValues) Refresh()

Refresh lazy values.

Jump to

Keyboard shortcuts

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