spectrum

package
v0.0.0-...-09ec4ce Latest Latest
Warning

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

Go to latest
Published: Dec 15, 2023 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

ZX Spectrum emulation core

Index

Constants

View Source
const (
	ScreenWidth  = 256
	ScreenHeight = 192

	BytesPerLine      = ScreenWidth / 8 // =32
	BytesPerLine_log2 = 5               // =log2(BytesPerLine)

	ScreenWidth_Attr      = ScreenWidth / 8  // =32
	ScreenWidth_Attr_log2 = 5                // =log2(ScreenWidth_Attr)
	ScreenHeight_Attr     = ScreenHeight / 8 // =24

	ScreenBorderX = 32
	ScreenBorderY = 32

	// Screen dimensions, including the border
	TotalScreenWidth  = ScreenWidth + ScreenBorderX*2
	TotalScreenHeight = ScreenHeight + ScreenBorderY*2

	SCREEN_BASE_ADDR = 0x4000
	ATTR_BASE_ADDR   = 0x5800
)
View Source
const (
	PIXELS_PER_TSTATE      = 2 // The number of screen pixels painted per T-state
	PIXELS_PER_TSTATE_LOG2 = 1 // = Log2(PIXELS_PER_TSTATE)

	// Horizontal
	LINE_SCREEN       = ScreenWidth / PIXELS_PER_TSTATE // 128 T states of screen
	LINE_RIGHT_BORDER = 24                              // 24 T states of right border
	LINE_RETRACE      = 48                              // 48 T states of horizontal retrace
	LINE_LEFT_BORDER  = 24                              // 24 T states of left border

	TSTATES_PER_LINE = (LINE_RIGHT_BORDER + LINE_SCREEN + LINE_LEFT_BORDER + LINE_RETRACE) // 224 T states

	FIRST_SCREEN_BYTE = 14336 // T-state when the first byte of the screen (16384) is displayed

	// Vertical
	LINES_TOP     = 64
	LINES_SCREEN  = ScreenHeight
	LINES_BOTTOM  = 56
	BORDER_TOP    = ScreenBorderY
	BORDER_BOTTOM = ScreenBorderY

	// The T-state which corresponds to pixel (0,0) on the host-machine display.
	// That pixel belongs to the border.
	DISPLAY_START            = (FIRST_SCREEN_BYTE - TSTATES_PER_LINE*BORDER_TOP - ScreenBorderX/PIXELS_PER_TSTATE + BORDER_TSTATE_ADJUSTMENT)
	BORDER_TSTATE_ADJUSTMENT = 2
)

Spectrum 48k video timings

View Source
const (
	KEMPSTON_FIRE = iota
	KEMPSTON_UP
	KEMPSTON_DOWN
	KEMPSTON_LEFT
	KEMPSTON_RIGHT
)
View Source
const (
	KEY_1 = iota
	KEY_2
	KEY_3
	KEY_4
	KEY_5
	KEY_6
	KEY_7
	KEY_8
	KEY_9
	KEY_0

	KEY_Q
	KEY_W
	KEY_E
	KEY_R
	KEY_T
	KEY_Y
	KEY_U
	KEY_I
	KEY_O
	KEY_P

	KEY_A
	KEY_S
	KEY_D
	KEY_F
	KEY_G
	KEY_H
	KEY_J
	KEY_K
	KEY_L
	KEY_Enter

	KEY_CapsShift
	KEY_Z
	KEY_X
	KEY_C
	KEY_V
	KEY_B
	KEY_N
	KEY_M
	KEY_SymbolShift
	KEY_Space
)

Logical key codes

View Source
const (
	TAPE_DRIVE_START = iota
	TAPE_DRIVE_STOP
	TAPE_DRIVE_PAUSE
	TAPE_DRIVE_LEADER
	TAPE_DRIVE_SYNC
	TAPE_DRIVE_NEWBIT
	TAPE_DRIVE_HALF2
	TAPE_DRIVE_PAUSE_STOP
	TAPE_DRIVE_NEWBYTE
)
View Source
const (
	TAPE_LEADER               = 2168
	TAPE_FIRST_SYNC           = 667
	TAPE_SECOND_SYNC          = 735
	TAPE_SET_BIT              = 1710
	TAPE_UNSET_BIT            = 855
	TAPE_HEADER_LEADER_PULSES = 8063
	TAPE_DATA_LEADER_PULSES   = 3223
	TAPE_PAUSE                = 3500000
)
View Source
const DefaultFPS = 50.08
View Source
const InterruptLength = 32 // How long does an interrupt last in T-states
View Source
const MAX_AUDIO_LEVEL = 3
View Source
const TAPE_ACCELERATION_IN_FPS = DefaultFPS * 20
View Source
const TStatesPerFrame = 69888 // Number of T-states per frame

Variables

View Source
var Audio16_Table = [4]float32{
	0,
	0x7fff * (Voltage_Issue2[1] - Voltage_Issue2[0]) / (Voltage_Issue2[3] - Voltage_Issue2[0]),
	0x7fff * (Voltage_Issue2[2] - Voltage_Issue2[0]) / (Voltage_Issue2[3] - Voltage_Issue2[0]),
	0x7fff,
}

A table for converting the "audio level" to a 16-bit signed value. Note: Users of this table can assume that 'Audio16_Table[0]' equals to zero.

View Source
var DefaultUserDir = path.Join(os.Getenv("HOME"), ".config", "gospeccy")
View Source
var Palette [16]uint32 = [16]uint32{
	RGBA{000, 000, 000, 255}.value32(),
	RGBA{000, 000, 192, 255}.value32(),
	RGBA{192, 000, 000, 255}.value32(),
	RGBA{192, 000, 192, 255}.value32(),
	RGBA{000, 192, 000, 255}.value32(),
	RGBA{000, 192, 192, 255}.value32(),
	RGBA{192, 192, 000, 255}.value32(),
	RGBA{192, 192, 192, 255}.value32(),
	RGBA{000, 000, 000, 255}.value32(),
	RGBA{000, 000, 255, 255}.value32(),
	RGBA{255, 000, 000, 255}.value32(),
	RGBA{255, 000, 255, 255}.value32(),
	RGBA{000, 255, 000, 255}.value32(),
	RGBA{000, 255, 255, 255}.value32(),
	RGBA{255, 255, 000, 255}.value32(),
	RGBA{255, 255, 255, 255}.value32(),
}
View Source
var SDL_KeyMap = map[string][]uint{
	"0": []uint{KEY_0},
	"1": []uint{KEY_1},
	"2": []uint{KEY_2},
	"3": []uint{KEY_3},
	"4": []uint{KEY_4},
	"5": []uint{KEY_5},
	"6": []uint{KEY_6},
	"7": []uint{KEY_7},
	"8": []uint{KEY_8},
	"9": []uint{KEY_9},

	"a": []uint{KEY_A},
	"b": []uint{KEY_B},
	"c": []uint{KEY_C},
	"d": []uint{KEY_D},
	"e": []uint{KEY_E},
	"f": []uint{KEY_F},
	"g": []uint{KEY_G},
	"h": []uint{KEY_H},
	"i": []uint{KEY_I},
	"j": []uint{KEY_J},
	"k": []uint{KEY_K},
	"l": []uint{KEY_L},
	"m": []uint{KEY_M},
	"n": []uint{KEY_N},
	"o": []uint{KEY_O},
	"p": []uint{KEY_P},
	"q": []uint{KEY_Q},
	"r": []uint{KEY_R},
	"s": []uint{KEY_S},
	"t": []uint{KEY_T},
	"u": []uint{KEY_U},
	"v": []uint{KEY_V},
	"w": []uint{KEY_W},
	"x": []uint{KEY_X},
	"y": []uint{KEY_Y},
	"z": []uint{KEY_Z},

	"return":      []uint{KEY_Enter},
	"space":       []uint{KEY_Space},
	"left shift":  []uint{KEY_CapsShift},
	"right shift": []uint{KEY_CapsShift},
	"left ctrl":   []uint{KEY_SymbolShift},
	"right ctrl":  []uint{KEY_SymbolShift},

	"left":      []uint{KEY_CapsShift, KEY_5},
	"down":      []uint{KEY_CapsShift, KEY_6},
	"up":        []uint{KEY_CapsShift, KEY_7},
	"right":     []uint{KEY_CapsShift, KEY_8},
	"backspace": []uint{KEY_CapsShift, KEY_0},

	"-": []uint{KEY_SymbolShift, KEY_J},

	"=": []uint{KEY_SymbolShift, KEY_L},

	"[": []uint{KEY_SymbolShift, KEY_8},
	"]": []uint{KEY_SymbolShift, KEY_9},
	";": []uint{KEY_SymbolShift, KEY_O},

	"'": []uint{KEY_SymbolShift, KEY_7},

	",": []uint{KEY_SymbolShift, KEY_N},
	".": []uint{KEY_SymbolShift, KEY_M},
	"/": []uint{KEY_SymbolShift, KEY_V},

	"[0]": []uint{KEY_0},
	"[1]": []uint{KEY_1},
	"[2]": []uint{KEY_2},
	"[3]": []uint{KEY_3},
	"[4]": []uint{KEY_4},
	"[5]": []uint{KEY_5},
	"[6]": []uint{KEY_6},
	"[7]": []uint{KEY_7},
	"[8]": []uint{KEY_8},
	"[9]": []uint{KEY_9},
	"[*]": []uint{KEY_SymbolShift, KEY_B},
	"[-]": []uint{KEY_SymbolShift, KEY_J},
	"[+]": []uint{KEY_SymbolShift, KEY_K},
	"[/]": []uint{KEY_SymbolShift, KEY_V},
}
View Source
var Voltage_Issue2 = [4]float32{
	0.39,
	0.73,
	3.66,
	3.79,
}

Voltage levels on pin 28 of the ULA chip after an out to port 0xFE, with no input signal on the EAR socket. Issue 2 Spectrums. Source: http://www.worldofspectrum.org/faq/reference/48kreference.htm

The array is indexed by [bits 3&4 of the value sent to the port].

View Source
var Voltage_Issue3 = [4]float32{
	0.34,
	0.66,
	3.56,
	3.70,
}

Voltage levels on pin 28 of the ULA chip after an out to port 0xFE, with no input signal on the EAR socket. Issue 3 Spectrums. Source: http://www.worldofspectrum.org/faq/reference/48kreference.htm

The array is indexed by [bits 3&4 of the value sent to the port].

Functions

func AddCustomSearchPath

func AddCustomSearchPath(path string)

func Assert

func Assert(condition bool)

Panic if condition is false

func DownloadPath

func DownloadPath() string

func Drain

func Drain(ticker *time.Ticker)

func FontPath

func FontPath(fileName string) (string, error)

Return a valid path for the specified font file, or the original filename if the search did not find anything.

An error is returned if the search could not proceed.

The search is performed in this order: 1. ./fonts/ 2. $HOME/.config/gospeccy/fonts/ 3. $GOPATH/src/github.com/remogatto/gospeccy/fonts/ 4. Custom search paths

func InstallSignalHandler

func InstallSignalHandler(handler SignalHandler)

Installs the specified handler. Trying to re-install an already installed handler is effectively a NOOP.

func ProgramPath

func ProgramPath(fileName string) (string, error)

Return a valid path for the file based on its extension, or the original filename if the search did not find anything.

An error is returned if the search could not proceed.

The search is performed in this order: 1. ./programs/ 2. $GOPATH/src/github.com/remogatto/gospeccy/programs/ 3. Custom search paths 4. Download path

func ReadROM

func ReadROM(path string) (*[0x4000]byte, error)

Reads the 16KB ROM from the specified file

func SameBorderEvents

func SameBorderEvents(l1, l2 []BorderEvent) bool

func ScriptPath

func ScriptPath(fileName string) (string, error)

Return a valid path for the specified script, or the original filename if the search did not find anything.

An error is returned if the search could not proceed.

The search is performed in this order: 1. ./scripts/ 2. $HOME/.config/gospeccy/scripts/ 3. $GOPATH/src/github.com/remogatto/gospeccy/scripts/ 4. Custom search paths

func SetDownloadPath

func SetDownloadPath(path string)

func SystemRomPath

func SystemRomPath(fileName string) (string, error)

Returns a valid path for the 48k system ROM, or the original filename if the search did not find anything.

An error is returned if the search could not proceed.

The search is performed in this order: 1. ./roms/ 2. $HOME/.config/gospeccy/roms/ 3. $GOPATH/src/github.com/remogatto/gospeccy/roms/ 4. Custom search paths

func UninstallSignalHandler

func UninstallSignalHandler(handler SignalHandler)

Uninstalls the specified handler. Trying to uninstall an non-existent handler is effectively a NOOP.

func WosGet

func WosGet(app *Application, stdout io.Writer, url string) (string, error)

Download from [ftp.worldofspectrum.org]. An URL can be obtained by calling function WosQuery.

Types

type Application

type Application struct {
	HasTerminated chan byte // This channel is closed after the whole application has terminated

	Verbose         bool
	VerboseShutdown bool

	CreationTime time.Time // The time when this Application object was created
	// contains filtered or unexported fields
}

func NewApplication

func NewApplication() *Application

func (*Application) GetMessageOutput

func (app *Application) GetMessageOutput() MessageOutput

Get the current MessageOutput

func (*Application) NewEventLoop

func (app *Application) NewEventLoop() *EventLoop

func (*Application) PrintfMsg

func (app *Application) PrintfMsg(format string, a ...interface{})

func (*Application) RequestExit

func (app *Application) RequestExit()

func (*Application) SetMessageOutput

func (app *Application) SetMessageOutput(out MessageOutput) MessageOutput

Replaces the MessageOutput, and returns the previous MessageOutput

func (*Application) Terminated

func (app *Application) Terminated() bool

func (*Application) TerminationInProgress

func (app *Application) TerminationInProgress() bool

type Attr_4bit

type Attr_4bit byte

The lower 4 bits define the paper, the higher 4 bits define the ink. Note that the paper is in the *lower* half. There is no flash bit.

type AudioData

type AudioData struct {
	// The FPS (frames per second) value that applies to this AudioData object
	FPS float32

	BeeperEvents []BeeperEvent
}

This is the primary structure for sending audio data from the Z80 CPU emulation core to an audio device.

type AudioReceiver

type AudioReceiver interface {
	GetAudioDataChannel() chan<- *AudioData

	// Closes the audio device associated with this AudioReceiver
	Close()
}

Interface to an audio device awaiting audio data

type BeeperEvent

type BeeperEvent struct {
	// The moment when the beeper-event occurred.
	// It is the number of T-states since the beginning of the frame.
	TState int

	// The beeper level (0 .. MAX_AUDIO_LEVEL)
	Level byte
}

func (*BeeperEvent) GetTState

func (e *BeeperEvent) GetTState() int

type BorderEvent

type BorderEvent struct {
	// The moment when the border color was changed.
	// It is the number of T-states since the beginning of the frame.
	TState int

	// The new border color
	Color byte
}

func (*BorderEvent) GetTState

func (e *BorderEvent) GetTState() int

type Cmd_AddAudioReceiver

type Cmd_AddAudioReceiver struct {
	Receiver AudioReceiver
}

type Cmd_AddDisplay

type Cmd_AddDisplay struct {
	Display DisplayReceiver
}

type Cmd_CloseAllAudioReceivers

type Cmd_CloseAllAudioReceivers struct {
	Finished chan<- byte
}

type Cmd_CloseAllDisplays

type Cmd_CloseAllDisplays struct {
	Finished chan<- byte
}

type Cmd_GetNumAudioReceivers

type Cmd_GetNumAudioReceivers struct {
	N chan<- uint
}

type Cmd_GetNumDisplayReceivers

type Cmd_GetNumDisplayReceivers struct {
	N chan<- uint
}

type Cmd_KeyPress

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

type Cmd_Load

type Cmd_Load struct {
	InformalFilename string // This is only used for logging purposes
	Program          interface{}
	ErrChan          chan<- error
}

type Cmd_LoadSnapshot

type Cmd_LoadSnapshot struct {
	InformalFilename string // This is only used for logging purposes
	Snapshot         formats.Snapshot
	ErrChan          chan<- error
}

type Cmd_MakeSnapshot

type Cmd_MakeSnapshot struct {
	Chan chan<- *formats.FullSnapshot
}

type Cmd_MakeVideoMemoryDump

type Cmd_MakeVideoMemoryDump struct {
	Chan chan<- []byte
}

type Cmd_RenderFrame

type Cmd_RenderFrame struct {
	// This channel (if not nil) will receive the real time when the rendering finished.
	//
	// If the list of host-machine displays is empty, the time only includes the emulation.
	// If the list of host-machine displays is non-empty, the time also includes host-machine
	// rendering. The sent time represents the moment of when the screen data reached
	// the host-machine display. On Linux this usually means: the moment right after
	// all pixels have been sent to the X server.
	// If there are multiple displays, the time includes the 1st display only.
	//
	// The time is obtained via a call to time.Nanoseconds().
	CompletionTime_orNil chan<- time.Time
}

type Cmd_Reset

type Cmd_Reset struct {
	// This channel will receive [a channel X which will receive 'true'
	// when it is detected that the system ROM is loaded].
	// The channel X will receive 'false' if the emulated machine is reset before
	// the detection process ends.
	SystemROMLoaded_orNil chan<- <-chan bool
}

type Cmd_SendLoad

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

type Cmd_SetAcceleratedLoad

type Cmd_SetAcceleratedLoad struct {
	// Set accelerated tape load on/off
	Enable bool
}

type Cmd_SetFPS

type Cmd_SetFPS struct {
	NewFPS       float32
	OldFPS_orNil chan<- float32
}

type Cmd_SetUlaEmulationAccuracy

type Cmd_SetUlaEmulationAccuracy struct {
	AccurateEmulation bool
}

type DisplayData

type DisplayData struct {
	Bitmap [BytesPerLine * ScreenHeight]byte          // Linear y-coordinate
	Attr   [BytesPerLine * ScreenHeight]Attr_4bit     // Linear y-coordinate
	Dirty  [ScreenWidth_Attr * ScreenHeight_Attr]bool // The 8x8 rectangular region was modified, either the bitmap or the attr

	BorderEvents []BorderEvent

	// From structure Cmd_RenderFrame
	CompletionTime_orNil chan<- time.Time
}

This is the primary structure for sending display changes from the Z80 CPU emulation core to a rendering backend. The data is already preprocessed, to make the rendering-backend's code simpler and faster.

The content of 'bitmap' and 'attr' corresponding to non-dirty regions is unspecified.

type DisplayInfo

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

type DisplayReceiver

type DisplayReceiver interface {
	GetDisplayDataChannel() chan<- *DisplayData

	// Closes the display associated with this DisplayReceiver
	Close()
}

Interface to a rendering backend awaiting display changes

type EventLoop

type EventLoop struct {

	// A symbolic name associated to the EventLoop (useful for
	// debugging).
	Name string

	// If [this channel receives a value] then [this event-loop
	// should pause].  As a response, after this event-loop
	// actually pauses, a value will appear on this channel.
	Pause chan byte

	// Constraint: A value can be sent to this channel only after
	// this event-loop has been paused.
	//
	// If [this channel receives a value] then [this event-loop
	// should terminate].  As a response, after this event-loop
	// actually terminates, a value will appear on this channel.
	Terminate chan byte
	// contains filtered or unexported fields
}

func (*EventLoop) App

func (e *EventLoop) App() *Application

func (*EventLoop) Delete

func (e *EventLoop) Delete() <-chan byte

Unregister the EventLoop from the Application. When the process finishes, the returned new channel will receive a value.

type FrameStatusOfPorts

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

type Joystick

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

func NewJoystick

func NewJoystick() *Joystick

func (*Joystick) GetState

func (joystick *Joystick) GetState() byte

func (*Joystick) KempstonDown

func (joystick *Joystick) KempstonDown(logicalCode uint)

func (*Joystick) KempstonUp

func (joystick *Joystick) KempstonUp(logicalCode uint)

func (*Joystick) SetState

func (joystick *Joystick) SetState(state byte)

type Keyboard

type Keyboard struct {
	CommandChannel chan interface{}
	// contains filtered or unexported fields
}

func NewKeyboard

func NewKeyboard() *Keyboard

func (*Keyboard) GetKeyState

func (keyboard *Keyboard) GetKeyState(row uint) byte

func (*Keyboard) KeyDown

func (keyboard *Keyboard) KeyDown(logicalKeyCode uint)

func (*Keyboard) KeyPress

func (keyboard *Keyboard) KeyPress(logicalKeyCode uint) chan bool

func (*Keyboard) KeyPressSequence

func (keyboard *Keyboard) KeyPressSequence(logicalKeyCodes ...uint) chan bool

func (*Keyboard) KeyUp

func (keyboard *Keyboard) KeyUp(logicalKeyCode uint)

func (*Keyboard) SetKeyState

func (keyboard *Keyboard) SetKeyState(row uint, state byte)

type Memory

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

func NewMemory

func NewMemory() *Memory

func (*Memory) ContendRead

func (memory *Memory) ContendRead(address uint16, time int)

func (*Memory) ContendReadNoMreq

func (memory *Memory) ContendReadNoMreq(address uint16, time int)

func (*Memory) ContendReadNoMreq_loop

func (memory *Memory) ContendReadNoMreq_loop(address uint16, time int, count uint)

func (*Memory) ContendWriteNoMreq

func (memory *Memory) ContendWriteNoMreq(address uint16, time int)

func (*Memory) ContendWriteNoMreq_loop

func (memory *Memory) ContendWriteNoMreq_loop(address uint16, time int, count uint)

func (*Memory) Data

func (memory *Memory) Data() []byte

func (*Memory) Read

func (memory *Memory) Read(address uint16) byte

func (*Memory) ReadByte

func (memory *Memory) ReadByte(address uint16) byte

func (*Memory) ReadByteInternal

func (memory *Memory) ReadByteInternal(address uint16) byte

func (*Memory) Write

func (memory *Memory) Write(address uint16, value byte, protectROM bool)

func (*Memory) WriteByte

func (memory *Memory) WriteByte(address uint16, b byte)

func (*Memory) WriteByteInternal

func (memory *Memory) WriteByteInternal(address uint16, b byte)

type MessageOutput

type MessageOutput interface {
	// Prints a single-line message.
	// If the format string does not end with the new-line character,
	// the new-line character is appended automatically.
	PrintfMsg(format string, a ...interface{})
}

type Ports

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

func NewPorts

func NewPorts() *Ports

func (*Ports) ContendPortPostio

func (p *Ports) ContendPortPostio(address uint16)

func (*Ports) ContendPortPreio

func (p *Ports) ContendPortPreio(address uint16)

func (*Ports) ReadPort

func (p *Ports) ReadPort(address uint16) byte

func (*Ports) ReadPortInternal

func (p *Ports) ReadPortInternal(address uint16, contend bool) byte

func (*Ports) WritePort

func (p *Ports) WritePort(address uint16, b byte)

func (*Ports) WritePortInternal

func (p *Ports) WritePortInternal(address uint16, b byte, contend bool)

type RGBA

type RGBA struct {
	R, G, B, A byte
}

type RomType

type RomType int
const (
	ROM_UNKNOWN RomType = iota
	ROM_OPENSE          // OpenSE BASIC (http://www.worldofspectrum.org/infoseekid.cgi?id=0027510)
)

type SignalHandler

type SignalHandler interface {
	// Function to be called upon receiving an os.Signal.
	//
	// A single signal is passed to all installed signal handlers.
	// The [order in which this function is called in respect to other handlers] is unspecified.
	HandleSignal(signal os.Signal)
}

type Spectrum48k

type Spectrum48k struct {
	Cpu    *z80.Z80
	Memory *Memory

	Keyboard *Keyboard
	Joystick *Joystick

	Ports *Ports

	CommandChannel chan<- interface{}
	// contains filtered or unexported fields
}

func NewSpectrum48k

func NewSpectrum48k(app *Application, rom [0x4000]byte) *Spectrum48k

Creates a new speccy object and starts its command-loop goroutine.

The returned object's CommandChannel can be used to configure the emulated machine before starting the emulation-loop and also to configure the machine while the emulation-loop is running.

To start the actual emulation-loop, create a separate goroutine for running the object's EmulatorLoop function.

func (*Spectrum48k) Close

func (speccy *Spectrum48k) Close()

Turn off the machine

func (*Spectrum48k) EmulatorLoop

func (speccy *Spectrum48k) EmulatorLoop()

Sends 'Cmd_RenderFrame' commands to the 'speccy' object in regular intervals. The interval depends on the value of FPS (frames per second).

This function should run in a separate goroutine.

func (*Spectrum48k) GetCurrentFPS

func (speccy *Spectrum48k) GetCurrentFPS() float32

Get current FPS

func (*Spectrum48k) GetEmulationEfficiency

func (speccy *Spectrum48k) GetEmulationEfficiency() uint

Returns the average number of host-CPU instructions required to execute one Z80 instruction. Returns zero if this information is not available.

func (*Spectrum48k) MakeSnapshot

func (speccy *Spectrum48k) MakeSnapshot() *formats.FullSnapshot

func (*Spectrum48k) TapeDrive

func (speccy *Spectrum48k) TapeDrive() *TapeDrive

Return the TapeDrive instance

type Tape

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

func NewTape

func NewTape(tap *formats.TAP) *Tape

func NewTapeFromFile

func NewTapeFromFile(filename string) (*Tape, error)

func (*Tape) At

func (tape *Tape) At(pos uint) byte

type TapeDrive

type TapeDrive struct {
	AcceleratedLoad    bool
	NotifyLoadComplete bool
	// contains filtered or unexported fields
}

func NewTapeDrive

func NewTapeDrive() *TapeDrive

func (*TapeDrive) Insert

func (tapeDrive *TapeDrive) Insert(tape *Tape)

func (*TapeDrive) LoadComplete

func (tapeDrive *TapeDrive) LoadComplete() <-chan bool

func (*TapeDrive) Play

func (tapeDrive *TapeDrive) Play()

func (*TapeDrive) Stop

func (tapeDrive *TapeDrive) Stop()

type ULA

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

func NewULA

func NewULA() *ULA

type WosRecord

type WosRecord struct {
	Title       string
	MachineType string   // "ZX Spectrum 48K", "ZX Spectrum 48K/128K", ...
	Publication string   // "Freeware", "Commercial", "unknown", ...
	FtpFiles    []string // formerly ftp, now http://www.worldofspectrum.org/...
	Score       string   // "7.59 (24 votes)", "No votes yet"
}

Information about a game/demo/utility located at [www.worldofspectrum.org]

func WosQuery

func WosQuery(app *Application, query string) ([]WosRecord, error)

Query [www.worldofspectrum.org] for matching files

Jump to

Keyboard shortcuts

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