mirror of
https://github.com/JetSetIlly/Gopher2600.git
synced 2024-06-15 19:17:34 -04:00
updated go minimum version to 1.20
applied gofmt to source tree to update the documentation comments
This commit is contained in:
parent
73a9c91930
commit
178f05f17b
|
@ -23,9 +23,9 @@
|
|||
// As well as the filename, the Loader type allows the cartridge mapping to be
|
||||
// specified, if required. The simplest instantiation therefore is:
|
||||
//
|
||||
// cl := cartridgeloader.Loader{
|
||||
// Filename: "roms/Pitfall.bin",
|
||||
// }
|
||||
// cl := cartridgeloader.Loader{
|
||||
// Filename: "roms/Pitfall.bin",
|
||||
// }
|
||||
//
|
||||
// It is stronly preferred however, that the NewLoader() function is used to
|
||||
// initialise the Loader or important fields risk being initialised
|
||||
|
@ -36,7 +36,7 @@
|
|||
// cases the mapper will be "AUTO" to indicate that we don't know (or
|
||||
// particular care) what the mapping format is.
|
||||
//
|
||||
// File Extensions
|
||||
// # File Extensions
|
||||
//
|
||||
// The file extension of a file will specify the cartridge mapping and will
|
||||
// cause the emulation to use that mapping. Most 2600 ROM files have the
|
||||
|
@ -85,7 +85,7 @@
|
|||
//
|
||||
// Fingerprinting is not handled by the cartridlgeloader package.
|
||||
//
|
||||
// Hash
|
||||
// # Hash
|
||||
//
|
||||
// The Hash field of the Loader type contains the SHA1 value of the loaded
|
||||
// data. It is valid after the Load() function has completed successfully. If
|
||||
|
@ -99,7 +99,7 @@
|
|||
//
|
||||
// The hash value is invalid/unused in the case of streamed data
|
||||
//
|
||||
// Streaming
|
||||
// # Streaming
|
||||
//
|
||||
// For some cartridge types it is necessary to stream bytes from the file
|
||||
// rather than load them all at once. For these types of cartridges the Load()
|
||||
|
@ -111,21 +111,20 @@
|
|||
// For streaming to work NewLoader() must have been used to instantiate the
|
||||
// Loader type.
|
||||
//
|
||||
// Closing
|
||||
// # Closing
|
||||
//
|
||||
// Instances of Loader must be closed with Close() when it is no longer
|
||||
// required.
|
||||
//
|
||||
// OnInserted
|
||||
// # OnInserted
|
||||
//
|
||||
// The OnInserted field is used by some cartridges to indicate when the
|
||||
// cartridge data has been loaded into memory and something else needs to
|
||||
// happen that is outside of the scope of the cartridge package. Currently,
|
||||
// this is used by the Supercharder and PlusROM.
|
||||
//
|
||||
// Notification Hook
|
||||
// # Notification Hook
|
||||
//
|
||||
// Some cartridge mappers will generate notifications (see notification.Notify type). The
|
||||
// NotifcationHook can be specified in order to respond to those events.
|
||||
//
|
||||
package cartridgeloader
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
// Package debugger implements a reaonably comprehensive debugging tool.
|
||||
// Features include:
|
||||
//
|
||||
// - cartridge disassembly
|
||||
// - memory peek and poke
|
||||
// - cpu and video cycle stepping
|
||||
// - basic scripting
|
||||
// - breakpoints
|
||||
// - traps
|
||||
// - watches
|
||||
// - cartridge disassembly
|
||||
// - memory peek and poke
|
||||
// - cpu and video cycle stepping
|
||||
// - basic scripting
|
||||
// - breakpoints
|
||||
// - traps
|
||||
// - watches
|
||||
//
|
||||
// Some of these features come courtesy of other packages, described elsewhere,
|
||||
// and some are inherent in the gopher2600's emulation strategy, but all are
|
||||
|
|
|
@ -244,8 +244,8 @@ func (bp breakpoints) list() {
|
|||
|
||||
// parse token and add new breakpoint. for example:
|
||||
//
|
||||
// PC 0xf000
|
||||
// adds a new breakpoint to the PC
|
||||
// PC 0xf000
|
||||
// adds a new breakpoint to the PC
|
||||
//
|
||||
// in addition to the description in the HELP file, the breakpoint parser has
|
||||
// some additional features which should probably be removed. if only because
|
||||
|
|
|
@ -85,11 +85,11 @@ func (n node) usageString() string {
|
|||
// optimised in this case means the absence of superfluous group indicators.
|
||||
// for example:
|
||||
//
|
||||
// TEST [1 [2] [3] [4] [5]]
|
||||
// TEST [1 [2] [3] [4] [5]]
|
||||
//
|
||||
// is the same as:
|
||||
//
|
||||
// TEST [1 2 3 4 5]
|
||||
// TEST [1 2 3 4 5]
|
||||
//
|
||||
// note: string should not be called directly except as a recursive call
|
||||
// or as an initial call from String() and usageString().
|
||||
|
|
|
@ -39,23 +39,25 @@ import (
|
|||
// into a machine friendly representation
|
||||
//
|
||||
// Syntax
|
||||
// [ a ] required keyword
|
||||
// ( a ) optional keyword
|
||||
// [ a | b | ... ] required selection
|
||||
// ( a | b | ... ) optional selection
|
||||
//
|
||||
// [ a ] required keyword
|
||||
// ( a ) optional keyword
|
||||
// [ a | b | ... ] required selection
|
||||
// ( a | b | ... ) optional selection
|
||||
//
|
||||
// groups can be embedded in one another
|
||||
//
|
||||
// Placeholders
|
||||
// %N numeric value
|
||||
// %P irrational number value
|
||||
// %S string (numbers can be strings too)
|
||||
// %F file name
|
||||
//
|
||||
// %N numeric value
|
||||
// %P irrational number value
|
||||
// %S string (numbers can be strings too)
|
||||
// %F file name
|
||||
//
|
||||
// Placeholders can be labelled. For example:
|
||||
//
|
||||
// %<first name>S
|
||||
// %<age>N
|
||||
// %<first name>S
|
||||
// %<age>N
|
||||
func ParseCommandTemplate(template []string) (*Commands, error) {
|
||||
cmds := &Commands{
|
||||
cmds: make([]*node, 0, 10),
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
// of the Disassembly instance and will "survive" calls to the FromMemory() and
|
||||
// FromCartridge() functions.
|
||||
//
|
||||
// Segmented Cartridges
|
||||
// # Segmented Cartridges
|
||||
//
|
||||
// The disassembly package treats small bank sized (those less than 4k) by
|
||||
// performing the disassembly with the cartridge rooted at each origin point -
|
||||
|
|
|
@ -68,6 +68,7 @@ func (t table) String() string {
|
|||
}
|
||||
|
||||
// make sure symbols is normalised:
|
||||
//
|
||||
// no leading or trailing space
|
||||
// internal space compressed and replaced with underscores
|
||||
func (t *table) normaliseSymbol(symbol string) string {
|
||||
|
|
2
go.mod
2
go.mod
|
@ -1,6 +1,6 @@
|
|||
module github.com/jetsetilly/gopher2600
|
||||
|
||||
go 1.18
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/go-audio/audio v1.0.0
|
||||
|
|
|
@ -25,14 +25,13 @@
|
|||
// pixel width; Converted to SVG with the help of Inkscape's Trace Bitmap
|
||||
// function; and finally imported into an empty TTF file using FontForge.
|
||||
//
|
||||
// Licencing
|
||||
// # Licencing
|
||||
//
|
||||
// Gopher2600-Icons.ttf is licenced by Stephen Illingworth, under the Creative
|
||||
// Commons Attribution 4.0 International licence.
|
||||
//
|
||||
// https://creativecommons.org/licenses/by/4.0/legalcode
|
||||
//
|
||||
//
|
||||
// The FontAwesome font (fa-solid-900.ttf) was downloaded on 18th March 2020
|
||||
// from https://fontawesome.com/download using the "Free for Web" button. Full
|
||||
// URL was:
|
||||
|
@ -41,13 +40,11 @@
|
|||
//
|
||||
// FontAwesome is licenced under the Font Awesome Free License.
|
||||
//
|
||||
//
|
||||
// Hack-Regular was downloaded on 20th December 2021 from permalink URL:
|
||||
//
|
||||
// https://github.com/source-foundry/Hack/blob/a737c121cabb337fdfe655d8c7304729f351e30f/build/ttf/Hack-Regular.ttf
|
||||
//
|
||||
// Hack-Regular is licenced under the MIT License.
|
||||
//
|
||||
//
|
||||
// JetBrainsMono-Regular is licenced under the OFL-1.1 License
|
||||
package fonts
|
||||
|
|
|
@ -23,13 +23,13 @@
|
|||
//
|
||||
// For example, to create a framebuffer sequence with two textures:
|
||||
//
|
||||
// seq := NewSequence(2)
|
||||
// seq := NewSequence(2)
|
||||
//
|
||||
// The Setup() function must be called at least once after NewSequence() and
|
||||
// called as often as necessary to ensure the dimensions (width and height) are
|
||||
// correct.
|
||||
//
|
||||
// hasChanged := seq.Setup(800, 600)
|
||||
// hasChanged := seq.Setup(800, 600)
|
||||
//
|
||||
// Setup() returns true if the texture data has been recreated in accordance
|
||||
// with the new dimensions.
|
||||
|
@ -39,13 +39,12 @@
|
|||
// returned and can be used for presentation of as the input for the next call
|
||||
// to Process() (via the draw() function).
|
||||
//
|
||||
// texture := seq.Process(0, func() {
|
||||
// // 1. set up shader
|
||||
// // 2. OpenGL draw (eg. gl.DrawElements()
|
||||
// })
|
||||
// texture := seq.Process(0, func() {
|
||||
// // 1. set up shader
|
||||
// // 2. OpenGL draw (eg. gl.DrawElements()
|
||||
// })
|
||||
//
|
||||
// Note that much of the work of chaning a sequence of shaders must be
|
||||
// performed by the user of the package. The package does however, hide a lot
|
||||
// of detail behind the Process() and Setup() functions.
|
||||
//
|
||||
package framebuffer
|
||||
|
|
|
@ -211,8 +211,8 @@ func imguiBooleanButton(trueCol imgui.Vec4, falseCol imgui.Vec4, state bool, tex
|
|||
// imguiLabel(), you can use the empty string or use the double hash construct.
|
||||
// For example
|
||||
//
|
||||
// imgui.SliderInt("##foo", &v, s, e)
|
||||
// imguiLabel("My Slider")
|
||||
// imgui.SliderInt("##foo", &v, s, e)
|
||||
// imguiLabel("My Slider")
|
||||
func imguiLabel(text string) {
|
||||
imgui.AlignTextToFramePadding()
|
||||
imgui.Text(text)
|
||||
|
|
|
@ -28,14 +28,12 @@
|
|||
// 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
|
||||
//
|
||||
// col := lazyval.Playfield.ForegroundColor
|
||||
//
|
||||
// Writing the playfield values is done thought debugger's "raw event" system:
|
||||
//
|
||||
|
@ -43,7 +41,6 @@
|
|||
// lazyval.VCS.TIA.Video.Playfield.ForegroundColor = col
|
||||
// })
|
||||
//
|
||||
//
|
||||
// Implementation
|
||||
// --------------
|
||||
//
|
||||
|
@ -69,16 +66,16 @@
|
|||
// 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() ------------------
|
||||
// }
|
||||
// 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
|
||||
|
@ -102,8 +99,8 @@
|
|||
// 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)
|
||||
// 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
|
||||
|
@ -116,7 +113,6 @@
|
|||
// 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
|
||||
// -------------------------------
|
||||
//
|
||||
|
@ -131,5 +127,4 @@
|
|||
// setting the Wait flag to true.
|
||||
//
|
||||
// Use of "wait" should be kept to a minimum to ensure system responsiveness.
|
||||
//
|
||||
package lazyvalues
|
||||
|
|
|
@ -202,7 +202,7 @@ func (mc *CPU) LoadPC(directAddress uint16) error {
|
|||
// read8Bit returns 8bit value from the specified address
|
||||
//
|
||||
// side-effects:
|
||||
// * calls cycleCallback after memory read
|
||||
// - calls cycleCallback after memory read
|
||||
func (mc *CPU) read8Bit(address uint16, phantom bool) (uint8, error) {
|
||||
mc.PhantomMemAccess = phantom
|
||||
|
||||
|
@ -227,7 +227,7 @@ func (mc *CPU) read8Bit(address uint16, phantom bool) (uint8, error) {
|
|||
// read8BitZero returns 8bit value from the specified zero-page address
|
||||
//
|
||||
// side-effects:
|
||||
// * calls cycleCallback after memory read
|
||||
// - calls cycleCallback after memory read
|
||||
func (mc *CPU) read8BitZeroPage(address uint8) (uint8, error) {
|
||||
mc.PhantomMemAccess = false
|
||||
|
||||
|
@ -269,7 +269,7 @@ func (mc *CPU) write8Bit(address uint16, value uint8, phantom bool) error {
|
|||
// read16Bit returns 16bit value from the specified address
|
||||
//
|
||||
// side-effects:
|
||||
// * calls cycleCallback after each 8bit read
|
||||
// - calls cycleCallback after each 8bit read
|
||||
func (mc *CPU) read16Bit(address uint16) (uint16, error) {
|
||||
mc.PhantomMemAccess = false
|
||||
|
||||
|
@ -320,10 +320,10 @@ const (
|
|||
// read8BitPC reads 8 bits from the memory location pointed to by PC
|
||||
//
|
||||
// side-effects:
|
||||
// * updates program counter
|
||||
// * calls cycleCallback at end of function
|
||||
// * updates LastResult.ByteCount
|
||||
// * additional side effect updates LastResult as appropriate
|
||||
// - updates program counter
|
||||
// - calls cycleCallback at end of function
|
||||
// - updates LastResult.ByteCount
|
||||
// - additional side effect updates LastResult as appropriate
|
||||
func (mc *CPU) read8BitPC(effect read8BitPCeffect) error {
|
||||
v, err := mc.mem.Read(mc.PC.Address())
|
||||
|
||||
|
@ -381,12 +381,12 @@ func (mc *CPU) read8BitPC(effect read8BitPCeffect) error {
|
|||
// read16BitPC reads 16 bits from the memory location pointed to by PC
|
||||
//
|
||||
// side-effects:
|
||||
// * updates program counter
|
||||
// * calls cycleCallback after each 8 bit read
|
||||
// * updates LastResult.ByteCount
|
||||
// * updates InstructionData field, once before each call to cycleCallback
|
||||
// - no callback function because this function is only ever used
|
||||
// to read operands
|
||||
// - updates program counter
|
||||
// - calls cycleCallback after each 8 bit read
|
||||
// - updates LastResult.ByteCount
|
||||
// - updates InstructionData field, once before each call to cycleCallback
|
||||
// - no callback function because this function is only ever used
|
||||
// to read operands
|
||||
func (mc *CPU) read16BitPC() error {
|
||||
lo, err := mc.mem.Read(mc.PC.Address())
|
||||
if err != nil {
|
||||
|
@ -518,9 +518,9 @@ const (
|
|||
// ExecuteInstruction steps CPU forward one instruction. The basic process when
|
||||
// executing an instruction is this:
|
||||
//
|
||||
// 1. read opcode and look up instruction definition
|
||||
// 2. read operands (if any) according to the addressing mode of the instruction
|
||||
// 3. using the operator as a guide, perform the instruction on the data
|
||||
// 1. read opcode and look up instruction definition
|
||||
// 2. read operands (if any) according to the addressing mode of the instruction
|
||||
// 3. using the operator as a guide, perform the instruction on the data
|
||||
//
|
||||
// All instructions take at least 2 cycle. After each cycle, the
|
||||
// cycleCallback() function is run, thereby allowing the rest of the VCS
|
||||
|
|
|
@ -95,7 +95,7 @@ const (
|
|||
// the Value field formatted as a string with the condition that branch instructions
|
||||
// are formatted as:
|
||||
//
|
||||
// Value/Value+1
|
||||
// Value/Value+1
|
||||
//
|
||||
// We do not format any potential PageSensitive cycle.
|
||||
type Cycles struct {
|
||||
|
|
|
@ -26,5 +26,4 @@
|
|||
//
|
||||
// Currently supported cartridge types are listed in the cartridgeloader
|
||||
// package.
|
||||
//
|
||||
package cartridge
|
||||
|
|
|
@ -40,7 +40,7 @@ type m3e struct {
|
|||
}
|
||||
|
||||
// cartridges:
|
||||
// - Sokoboo
|
||||
// - Sokoboo
|
||||
func new3e(instance *instance.Instance, data []byte) (mapper.CartMapper, error) {
|
||||
cart := &m3e{
|
||||
instance: instance,
|
||||
|
|
|
@ -41,15 +41,16 @@ type m3ePlus struct {
|
|||
}
|
||||
|
||||
// should work with any size cartridge that is a multiple of 1024:
|
||||
// - tested with chess3E+20200519_3PQ6_SQ.bin
|
||||
// https://atariage.com/forums/topic/299157-chess/?do=findComment&comment=4541517
|
||||
//
|
||||
// - specifciation:
|
||||
// https://atariage.com/forums/topic/307914-3e-and-macros-are-your-friend/?tab=comments#comment-4561287
|
||||
// - tested with chess3E+20200519_3PQ6_SQ.bin
|
||||
// https://atariage.com/forums/topic/299157-chess/?do=findComment&comment=4541517
|
||||
//
|
||||
// - specifciation:
|
||||
// https://atariage.com/forums/topic/307914-3e-and-macros-are-your-friend/?tab=comments#comment-4561287
|
||||
//
|
||||
// cartridges:
|
||||
// - chess (Andrew Davie)
|
||||
// cartridges:
|
||||
//
|
||||
// - chess (Andrew Davie)
|
||||
func new3ePlus(instance *instance.Instance, data []byte) (mapper.CartMapper, error) {
|
||||
cart := &m3ePlus{
|
||||
instance: instance,
|
||||
|
|
|
@ -281,10 +281,10 @@ func (cart *atari) AddSuperchip(force bool) {
|
|||
}
|
||||
|
||||
// atari4k is the original and most straightforward format:
|
||||
// - Pitfall
|
||||
// - River Raid
|
||||
// - Barnstormer
|
||||
// - etc.
|
||||
// - Pitfall
|
||||
// - River Raid
|
||||
// - Barnstormer
|
||||
// - etc.
|
||||
type atari4k struct {
|
||||
atari
|
||||
}
|
||||
|
@ -338,11 +338,11 @@ func (cart *atari4k) AccessVolatile(addr uint16, data uint8, poke bool) error {
|
|||
}
|
||||
|
||||
// atari2k is the half-size cartridge of 2048 bytes:
|
||||
// - Combat
|
||||
// - Dragster
|
||||
// - Outlaw
|
||||
// - Surround
|
||||
// - early cartridges
|
||||
// - Combat
|
||||
// - Dragster
|
||||
// - Outlaw
|
||||
// - Surround
|
||||
// - early cartridges
|
||||
//
|
||||
// it also supports other cartridge sizes less than 4096 bytes
|
||||
type atari2k struct {
|
||||
|
@ -413,9 +413,9 @@ func (cart *atari2k) AccessVolatile(addr uint16, data uint8, poke bool) error {
|
|||
}
|
||||
|
||||
// atari8k (F8):
|
||||
// - ET
|
||||
// - Krull
|
||||
// - etc.
|
||||
// - ET
|
||||
// - Krull
|
||||
// - etc.
|
||||
type atari8k struct {
|
||||
atari
|
||||
}
|
||||
|
@ -509,10 +509,10 @@ func (cart *atari8k) WriteHotspots() map[uint16]mapper.CartHotspotInfo {
|
|||
}
|
||||
|
||||
// atari16k (F6):
|
||||
// - Crystal Castle
|
||||
// - RS Boxing
|
||||
// - Midnite Magic
|
||||
// - etc.
|
||||
// - Crystal Castle
|
||||
// - RS Boxing
|
||||
// - Midnite Magic
|
||||
// - etc.
|
||||
type atari16k struct {
|
||||
atari
|
||||
}
|
||||
|
|
|
@ -28,17 +28,16 @@ import (
|
|||
//
|
||||
// 12K:
|
||||
//
|
||||
// -FA: Used only by CBS. Similar to F8, except you have three 4K banks
|
||||
// instead of two. You select the desired bank via 1FF8, 1FF9, and 1FFA.
|
||||
// These carts also have 256 bytes of RAM mapped in at 1000-11FF. 1000-10FF
|
||||
// is the write port while 1100-11FF is the read port.
|
||||
//
|
||||
// -FA: Used only by CBS. Similar to F8, except you have three 4K banks
|
||||
// instead of two. You select the desired bank via 1FF8, 1FF9, and 1FFA.
|
||||
// These carts also have 256 bytes of RAM mapped in at 1000-11FF. 1000-10FF
|
||||
// is the write port while 1100-11FF is the read port.
|
||||
//
|
||||
// cartridges:
|
||||
// - Omega Race
|
||||
// - Mountain King
|
||||
// - Tunnel Runner
|
||||
// - Noice (scene demo)
|
||||
// - Omega Race
|
||||
// - Mountain King
|
||||
// - Tunnel Runner
|
||||
// - Noice (scene demo)
|
||||
//
|
||||
// US patent 4,485,457A describes the format in detail:
|
||||
//
|
||||
|
|
|
@ -37,8 +37,8 @@ import (
|
|||
// from bankswitch_sizes.txt:
|
||||
//
|
||||
// cartridges:
|
||||
// - MagiCard
|
||||
// - Video Lfe
|
||||
// - MagiCard
|
||||
// - Video Lfe
|
||||
//
|
||||
// and the reason why I implemented this format for Gopher2600:
|
||||
//
|
||||
|
|
|
@ -34,11 +34,10 @@ import (
|
|||
// for the third 1K. The last 1K always points to the last 1K of the ROM image
|
||||
// so that the cart always starts up in the exact same place.
|
||||
//
|
||||
//
|
||||
// cartridges:
|
||||
// - Montezuma's Revenge
|
||||
// - Lord of the Rings
|
||||
// - etc.
|
||||
// - Montezuma's Revenge
|
||||
// - Lord of the Rings
|
||||
// - etc.
|
||||
type parkerBros struct {
|
||||
instance *instance.Instance
|
||||
|
||||
|
|
|
@ -39,8 +39,8 @@ import (
|
|||
// since you can implement this with only one chip! (a 74LS173).
|
||||
//
|
||||
// cartridges:
|
||||
// - Miner2049
|
||||
// - River Patrol
|
||||
// - Miner2049
|
||||
// - River Patrol
|
||||
type tigervision struct {
|
||||
instance *instance.Instance
|
||||
|
||||
|
@ -58,7 +58,7 @@ type tigervision struct {
|
|||
}
|
||||
|
||||
// should work with any size cartridge that is a multiple of 2048:
|
||||
// - tested with 8k (Miner2049 etc.) and 32k (Genesis_Egypt demo).
|
||||
// - tested with 8k (Miner2049 etc.) and 32k (Genesis_Egypt demo).
|
||||
func newTigervision(instance *instance.Instance, data []byte) (mapper.CartMapper, error) {
|
||||
cart := &tigervision{
|
||||
instance: instance,
|
||||
|
|
|
@ -36,9 +36,9 @@ var biosFile = [...]string{
|
|||
const biosLogTag = "supercharger: bios"
|
||||
|
||||
// loadBIOS attempts to load BIOS from (in order of priority):
|
||||
// - current working directory
|
||||
// - the same directory as the tape/bin file
|
||||
// - the emulator's resource path
|
||||
// - current working directory
|
||||
// - the same directory as the tape/bin file
|
||||
// - the emulator's resource path
|
||||
func loadBIOS(path string) ([]uint8, error) {
|
||||
// current working directory
|
||||
for _, b := range biosFile {
|
||||
|
|
|
@ -26,45 +26,41 @@
|
|||
// is that the peripheral bus only ever writes to memory. The other buses are
|
||||
// bidirectional.
|
||||
//
|
||||
// PERIPHERALS
|
||||
//
|
||||
// PERIPHERALS
|
||||
// |
|
||||
// |
|
||||
// \/
|
||||
//
|
||||
// |
|
||||
// |
|
||||
// \/
|
||||
// periph bus
|
||||
//
|
||||
// periph bus
|
||||
// |
|
||||
// |
|
||||
// \/
|
||||
//
|
||||
// |
|
||||
// |
|
||||
// \/
|
||||
// CPU ---- cpu bus ---- MEMORY ---- chip bus ---- TIA
|
||||
// \
|
||||
// | \
|
||||
// | \---- RIOT
|
||||
//
|
||||
// CPU ---- cpu bus ---- MEMORY ---- chip bus ---- TIA
|
||||
// \
|
||||
// | \
|
||||
// | \---- RIOT
|
||||
// debugger bus
|
||||
//
|
||||
// debugger bus
|
||||
//
|
||||
// |
|
||||
// |
|
||||
//
|
||||
// DEBUGGER
|
||||
// |
|
||||
// |
|
||||
//
|
||||
// DEBUGGER
|
||||
//
|
||||
// The memory itself is divided into areas, defined in the memorymap package.
|
||||
// Removing the periph bus and debugger bus from the picture, the above diagram
|
||||
// with memory areas added is as follows:
|
||||
//
|
||||
//
|
||||
// ===* TIA ---- chip bus ---- TIA
|
||||
// |
|
||||
// |===* RIOT ---- chip bus ---- RIOT
|
||||
// CPU ---- cpu bus -----
|
||||
// |===* PIA RAM
|
||||
// |
|
||||
// ==== Cartridge
|
||||
//
|
||||
// ===* TIA ---- chip bus ---- TIA
|
||||
// |
|
||||
// |===* RIOT ---- chip bus ---- RIOT
|
||||
// CPU ---- cpu bus -----
|
||||
// |===* PIA RAM
|
||||
// |
|
||||
// ==== Cartridge
|
||||
//
|
||||
// The asterisk indicates that addresses used by the CPU are mapped to the
|
||||
// primary mirror address. The memorymap package contains more detail on this.
|
||||
|
|
|
@ -91,8 +91,8 @@ const Memtop = uint16(0x1fff)
|
|||
//
|
||||
// Alternatively, the following is an effective way to index an array:
|
||||
//
|
||||
// addr := 0xf000
|
||||
// mem[addr & CartridgeBits] = 0xff
|
||||
// addr := 0xf000
|
||||
// mem[addr & CartridgeBits] = 0xff
|
||||
//
|
||||
// In the example, index zero of the mem array is assigned the value 0xff.
|
||||
const (
|
||||
|
|
|
@ -37,14 +37,13 @@ import (
|
|||
// "Stella Programmer's Guide" but they are readable anyway and are wired the
|
||||
// same as the collision and INPTx registers.
|
||||
//
|
||||
//
|
||||
// Explanation of how the TIADrivenPins mask affects the read value
|
||||
// ----------------------------------------------------------------
|
||||
//
|
||||
// If the CPU wants to read the contents of the CXM1P register, it can use the
|
||||
// address 0x0d to do so.
|
||||
//
|
||||
// LDA 0x01
|
||||
// LDA 0x01
|
||||
//
|
||||
// If there are no collisions (between missile 1 and either player, in this
|
||||
// case) than the value of the most significant bits are zero. The lower six
|
||||
|
@ -52,13 +51,13 @@ import (
|
|||
// when the data is put on the bus. The lower bits of the LDA operation are in
|
||||
// fact "left over" from the address. In our example, the lowest six bits are
|
||||
//
|
||||
// 0bxx000001
|
||||
// 0bxx000001
|
||||
//
|
||||
// meaning the the returned data is in fact 0x01 and not 0x00, as you might
|
||||
// expect. Things get interesting when we use mirrored addresses. If instead
|
||||
// of 0x01 we used the mirror address 0x11, the lowest six bits are:
|
||||
//
|
||||
// 0bxx01001
|
||||
// 0bxx01001
|
||||
//
|
||||
// meaning that the returned value is 0x11 and not (again, as you might expect)
|
||||
// 0x00 or even 0x01.
|
||||
|
@ -67,12 +66,12 @@ import (
|
|||
// Meaning that the top bits are not necessarily zero. Let's say there is a
|
||||
// collusion between missile 1 and player 0, the data before masking will be
|
||||
//
|
||||
// 0b01000000
|
||||
// 0b01000000
|
||||
//
|
||||
// If we used address 0x11 to load this value, we would in fact, get this
|
||||
// pattern (0x51 in hex):
|
||||
//
|
||||
// 0b01010001
|
||||
// 0b01010001
|
||||
//
|
||||
// Now, if all ROMs read and interpreted chip registers only as they're
|
||||
// supposed to (defails in the 2600 programmer's guide) then none of this would
|
||||
|
@ -86,7 +85,7 @@ import (
|
|||
// most-significant byte. So, if the requested address is 0x171, the bit
|
||||
// pattern for the address is:
|
||||
//
|
||||
// 0x0000000101110001
|
||||
// 0x0000000101110001
|
||||
//
|
||||
// the most significant byte in this pattern is 0x00000001 and so the data
|
||||
// retreived is AND-ed with that. The mapped address for 0x171 incidentally, is
|
||||
|
|
|
@ -30,9 +30,9 @@ const activityLength = 64
|
|||
// deriving conditions from two traces is convenient. for example, give two
|
||||
// traces A and B, a condition for event E might be:
|
||||
//
|
||||
// if A.hi() && B.lo2hi() {
|
||||
// E()
|
||||
// }
|
||||
// if A.hi() && B.lo2hi() {
|
||||
// E()
|
||||
// }
|
||||
type Trace struct {
|
||||
// a recent history of the i2c trace. wraps around at activityLength
|
||||
activity []float32
|
||||
|
|
|
@ -63,10 +63,9 @@ type PlugMonitor interface {
|
|||
// Implementations of Monitorable should also test peripherals that are
|
||||
// daisy-chained and call AttachPlusMonitor() as appropriate.
|
||||
//
|
||||
// if a, ok := periph.daisychain.(pluggin.Monitorable); ok {
|
||||
// a.AttachPlugMonitor(m)
|
||||
// }
|
||||
//
|
||||
// if a, ok := periph.daisychain.(pluggin.Monitorable); ok {
|
||||
// a.AttachPlugMonitor(m)
|
||||
// }
|
||||
type Monitorable interface {
|
||||
AttachPlugMonitor(m PlugMonitor)
|
||||
}
|
||||
|
|
|
@ -495,23 +495,23 @@ func (p *Ports) PokeField(fld string, v interface{}) {
|
|||
// the derived value of SWCHA. the value it should be if the RIOT logic has
|
||||
// proceeded normally (ie. no poking)
|
||||
//
|
||||
// SWCHA_W SWACNT <input> SWCHA
|
||||
// 0 0 1 1 ^SWCHA_W & ^SWACNT & <input>
|
||||
// 0 0 0 0
|
||||
// 0 1 1 0
|
||||
// 0 1 0 0
|
||||
// 1 0 1 1 SWCHA_W & ^SWACNT & <input>
|
||||
// 1 0 0 0
|
||||
// 1 1 1 1 SWCHA_W & SWACNT & <input>
|
||||
// 1 1 0 0
|
||||
// SWCHA_W SWACNT <input> SWCHA
|
||||
// 0 0 1 1 ^SWCHA_W & ^SWACNT & <input>
|
||||
// 0 0 0 0
|
||||
// 0 1 1 0
|
||||
// 0 1 0 0
|
||||
// 1 0 1 1 SWCHA_W & ^SWACNT & <input>
|
||||
// 1 0 0 0
|
||||
// 1 1 1 1 SWCHA_W & SWACNT & <input>
|
||||
// 1 1 0 0
|
||||
//
|
||||
// a := p.swcha_w
|
||||
// b := swacnt
|
||||
// c := p.swcha_mux
|
||||
// a := p.swcha_w
|
||||
// b := swacnt
|
||||
// c := p.swcha_mux
|
||||
//
|
||||
// (^a & ^b & c) | (a & ^b & c) | (a & b & c)
|
||||
// (a & c & (^b|b)) | (^a & ^b & c)
|
||||
// (a & c) | (^a & ^b & c)
|
||||
// (^a & ^b & c) | (a & ^b & c) | (a & b & c)
|
||||
// (a & c & (^b|b)) | (^a & ^b & c)
|
||||
// (a & c) | (^a & ^b & c)
|
||||
func (p *Ports) deriveSWCHA() uint8 {
|
||||
swacnt := p.riot.ChipRefer(chipbus.SWACNT)
|
||||
return (p.swcha_w & p.swcha_mux) | (^p.swcha_w & ^swacnt & p.swcha_mux)
|
||||
|
@ -520,25 +520,25 @@ func (p *Ports) deriveSWCHA() uint8 {
|
|||
// the derived value of SWCHB. the value it should be if the RIOT logic has
|
||||
// proceeded normally (ie. no poking).
|
||||
//
|
||||
// SWCHB_W SWBCNT <input> SWCHB
|
||||
// 0 0 1 1 ^SWCHB_W & ^SWBCNT & <input>
|
||||
// 0 0 0 0
|
||||
// 0 1 1 0
|
||||
// 0 1 0 0
|
||||
// 1 0 1 1 SWCHB_W & ^SWBCNT & <input>
|
||||
// 1 0 0 0
|
||||
// 1 1 1 1 SWCHB_W & SWBCNT & <input>
|
||||
// 1 1 0 1 SWCHB_W & SWBCNT & ^<input>
|
||||
// SWCHB_W SWBCNT <input> SWCHB
|
||||
// 0 0 1 1 ^SWCHB_W & ^SWBCNT & <input>
|
||||
// 0 0 0 0
|
||||
// 0 1 1 0
|
||||
// 0 1 0 0
|
||||
// 1 0 1 1 SWCHB_W & ^SWBCNT & <input>
|
||||
// 1 0 0 0
|
||||
// 1 1 1 1 SWCHB_W & SWBCNT & <input>
|
||||
// 1 1 0 1 SWCHB_W & SWBCNT & ^<input>
|
||||
//
|
||||
// (The last entry of the truth table is different to the truth table for SWCHA)
|
||||
// (The last entry of the truth table is different to the truth table for SWCHA)
|
||||
//
|
||||
// a := p.swchb_w
|
||||
// b := swbcnt
|
||||
// c := p.swchb_raw
|
||||
// a := p.swchb_w
|
||||
// b := swbcnt
|
||||
// c := p.swchb_raw
|
||||
//
|
||||
// (^a & ^b & c) | (a & ^b & c) | (a & b & c) | (a & b & ^c)
|
||||
// (^a & ^b & c) | (a & ^b & c) | (a & b)
|
||||
// (^b & c) | (a & b)
|
||||
// (^a & ^b & c) | (a & ^b & c) | (a & b & c) | (a & b & ^c)
|
||||
// (^a & ^b & c) | (a & ^b & c) | (a & b)
|
||||
// (^b & c) | (a & b)
|
||||
func (p *Ports) deriveSWCHB() uint8 {
|
||||
swbcnt := p.riot.ChipRefer(chipbus.SWBCNT)
|
||||
return (^swbcnt & p.swchb_raw) | (p.swchb_w & swbcnt)
|
||||
|
|
|
@ -25,12 +25,12 @@ import (
|
|||
|
||||
// Divider indicates how often (in CPU cycles) the timer value decreases.
|
||||
// the following rules apply:
|
||||
// * set to 1, 8, 64 or 1024 depending on which address has been
|
||||
// written to by the CPU
|
||||
// * is used to reset the cyclesRemaining
|
||||
// * is changed to 1 once value reaches 0
|
||||
// * is reset to its initial value of 1, 8, 64, or 1024 whenever INTIM
|
||||
// is read by the CPU
|
||||
// - set to 1, 8, 64 or 1024 depending on which address has been
|
||||
// written to by the CPU
|
||||
// - is used to reset the cyclesRemaining
|
||||
// - is changed to 1 once value reaches 0
|
||||
// - is reset to its initial value of 1, 8, 64, or 1024 whenever INTIM
|
||||
// is read by the CPU
|
||||
type Divider int
|
||||
|
||||
// List of valid Divider values.
|
||||
|
@ -265,10 +265,11 @@ func (tmr *Timer) Step() {
|
|||
// INTIM register on the cpubus - provided here for convenience.
|
||||
//
|
||||
// Supported fields:
|
||||
// intim (uint8)
|
||||
// timint (uint8)
|
||||
// ticksRemainging (int)
|
||||
// divider (timer.Divider)
|
||||
//
|
||||
// intim (uint8)
|
||||
// timint (uint8)
|
||||
// ticksRemainging (int)
|
||||
// divider (timer.Divider)
|
||||
func (tmr *Timer) PeekField(fld string) interface{} {
|
||||
switch fld {
|
||||
case "intim":
|
||||
|
|
|
@ -28,15 +28,14 @@ import (
|
|||
// a standard value that can be used to filter out expensive code paths within
|
||||
// a continueCheck() implementation. For example:
|
||||
//
|
||||
// performanceFilter++
|
||||
// if performanceFilter >= hardware.PerfomrmanceBrake {
|
||||
// performanceFilter = 0
|
||||
// if end_condition == true {
|
||||
// return govern.Ending, nill
|
||||
// }
|
||||
// performanceFilter++
|
||||
// if performanceFilter >= hardware.PerfomrmanceBrake {
|
||||
// performanceFilter = 0
|
||||
// if end_condition == true {
|
||||
// return govern.Ending, nill
|
||||
// }
|
||||
// return govern.Running, nill
|
||||
//
|
||||
// }
|
||||
// return govern.Running, nill
|
||||
const PerformanceBrake = 100
|
||||
|
||||
// Run sets the emulation running as quickly as possible
|
||||
|
|
|
@ -51,17 +51,17 @@
|
|||
// information about the frame can be acquired with GetFrameInfo(). FrameInfo
|
||||
// will also be sent to the PixelRenderers as appropriate.
|
||||
//
|
||||
// Screen Rolling
|
||||
// # Screen Rolling
|
||||
//
|
||||
// Screen rolling is not handled by the television package. However, the synced
|
||||
// argument of the NewFrame() function in the PixelRenderer and FrameTrigger
|
||||
// interfaces can be used to implement it if required. Something like this:
|
||||
//
|
||||
// 1) If Synced is false, note scanline of last plot (unsynedScanline)
|
||||
// 2) For every SetPixel() add unsyncedScanline to the Scanline value in
|
||||
// the SignalAttributes struct (adjustedScanline)
|
||||
// 3) Bring adjustedScanline into range by modulo ScanlinesTotal of the
|
||||
// current TV specification.
|
||||
// 1. If Synced is false, note scanline of last plot (unsynedScanline)
|
||||
// 2. For every SetPixel() add unsyncedScanline to the Scanline value in
|
||||
// the SignalAttributes struct (adjustedScanline)
|
||||
// 3. Bring adjustedScanline into range by modulo ScanlinesTotal of the
|
||||
// current TV specification.
|
||||
//
|
||||
// Recovery from a screen roll should also be emulated. A good way of doing
|
||||
// this is to reduce unsyncedScanline by a percentage (80% say) on synced
|
||||
|
@ -70,12 +70,12 @@
|
|||
// A good additionl policy would be to only roll if several, consecutive
|
||||
// unsynced frames are indicated.
|
||||
//
|
||||
// Concurrency
|
||||
// # Concurrency
|
||||
//
|
||||
// None of the functions in the Television type are safe to be called from
|
||||
// goroutines other than the one the type was created in.
|
||||
//
|
||||
// Logging
|
||||
// # Logging
|
||||
//
|
||||
// The television does no logging. This is because the television can be used
|
||||
// ephemerally and logging would be noisy. Callers of television package
|
||||
|
|
|
@ -23,40 +23,54 @@ import (
|
|||
// resizer handles the expansion of the visible area of the TV screen
|
||||
//
|
||||
// ROMs used to test resizing:
|
||||
// * good base cases
|
||||
// - Pitfall
|
||||
// - Hero
|
||||
//
|
||||
// * needs an additional (or two) scanlines to accommodate full screen
|
||||
// - Ladybug
|
||||
// - Man Goes Down
|
||||
// - good base cases
|
||||
//
|
||||
// * frame that needs to be resized after startup period
|
||||
// - Hack Em Hanglyman (pre-release)
|
||||
// - Pitfall
|
||||
//
|
||||
// * the occasional unsynced frame
|
||||
// - Hack Em Hanglyman (pre-release)
|
||||
// - Hero
|
||||
//
|
||||
// * lots of unsynced frames (during computer "thinking" period)
|
||||
// - Andrew Davies' Chess
|
||||
// - needs an additional (or two) scanlines to accommodate full screen
|
||||
//
|
||||
// * does not set VBLANK for pixels that are clearly not meant to be seen
|
||||
// these ROMs rely on the SafeTop and SafeBottom values being correct
|
||||
// - Communist Mutants From Space
|
||||
// - Tapper
|
||||
// - Spike's Peak
|
||||
// - Ladybug
|
||||
//
|
||||
// * ROMs that do not set VBLANK *at all*. in these cases the commit()
|
||||
// function uses the black top/bottom values rather than vblank top/bottom
|
||||
// values.
|
||||
// - Hack Em Hanglyman (release and pre-release)
|
||||
// - Legacy of the Beast
|
||||
// - Man Goes Down
|
||||
//
|
||||
// * ROMs that *do* set VBLANK but might be caught by the black top/bottom
|
||||
// rule if frameHasVBlank was incorrectly set
|
||||
// - aTaRSI (demo)
|
||||
// - Supercharger "rewind tape" screen
|
||||
// - frame that needs to be resized after startup period
|
||||
//
|
||||
// - Hack Em Hanglyman (pre-release)
|
||||
//
|
||||
// - the occasional unsynced frame
|
||||
//
|
||||
// - Hack Em Hanglyman (pre-release)
|
||||
//
|
||||
// - lots of unsynced frames (during computer "thinking" period)
|
||||
//
|
||||
// - Andrew Davies' Chess
|
||||
//
|
||||
// - does not set VBLANK for pixels that are clearly not meant to be seen
|
||||
// these ROMs rely on the SafeTop and SafeBottom values being correct
|
||||
//
|
||||
// - Communist Mutants From Space
|
||||
//
|
||||
// - Tapper
|
||||
//
|
||||
// - Spike's Peak
|
||||
//
|
||||
// - ROMs that do not set VBLANK *at all*. in these cases the commit()
|
||||
// function uses the black top/bottom values rather than vblank top/bottom
|
||||
// values.
|
||||
//
|
||||
// - Hack Em Hanglyman (release and pre-release)
|
||||
//
|
||||
// - Legacy of the Beast
|
||||
//
|
||||
// - ROMs that *do* set VBLANK but might be caught by the black top/bottom
|
||||
// rule if frameHasVBlank was incorrectly set
|
||||
//
|
||||
// - aTaRSI (demo)
|
||||
//
|
||||
// - Supercharger "rewind tape" screen
|
||||
type resizer struct {
|
||||
// candidate top/bottom values for an actual resize.
|
||||
//
|
||||
|
|
|
@ -21,11 +21,11 @@
|
|||
// from both projects was used as reference. Both projects are exactly
|
||||
// equivalent.
|
||||
//
|
||||
// 6502.ts (published under the MIT licence)
|
||||
// https://github.com/6502ts/6502.ts/blob/6f923e5fe693b82a2448ffac1f85aea9693cacff/src/machine/stella/tia/PCMAudio.ts
|
||||
// https://github.com/6502ts/6502.ts/blob/6f923e5fe693b82a2448ffac1f85aea9693cacff/src/machine/stella/tia/PCMChannel.ts
|
||||
// 6502.ts (published under the MIT licence)
|
||||
// https://github.com/6502ts/6502.ts/blob/6f923e5fe693b82a2448ffac1f85aea9693cacff/src/machine/stella/tia/PCMAudio.ts
|
||||
// https://github.com/6502ts/6502.ts/blob/6f923e5fe693b82a2448ffac1f85aea9693cacff/src/machine/stella/tia/PCMChannel.ts
|
||||
//
|
||||
// Stella (published under the GNU GPL v2.0 licence)
|
||||
// https://github.com/stella-emu/stella/blob/e6af23d6c12893dd17711002971087f28f87c31f/src/emucore/tia/Audio.cxx
|
||||
// https://github.com/stella-emu/stella/blob/e6af23d6c12893dd17711002971087f28f87c31f/src/emucore/tia/AudioChannel.cxx
|
||||
// Stella (published under the GNU GPL v2.0 licence)
|
||||
// https://github.com/stella-emu/stella/blob/e6af23d6c12893dd17711002971087f28f87c31f/src/emucore/tia/Audio.cxx
|
||||
// https://github.com/stella-emu/stella/blob/e6af23d6c12893dd17711002971087f28f87c31f/src/emucore/tia/AudioChannel.cxx
|
||||
package audio
|
||||
|
|
|
@ -28,13 +28,13 @@
|
|||
// Both 6502.ts and Stella source was used as reference. Both projects are
|
||||
// exactly equivalent.
|
||||
//
|
||||
// 6502.ts (published under the MIT licence)
|
||||
// https://github.com/6502ts/6502.ts/blob/6f923e5fe693b82a2448ffac1f85aea9693cacff/src/machine/stella/tia/PCMAudio.ts
|
||||
// https://github.com/6502ts/6502.ts/blob/6f923e5fe693b82a2448ffac1f85aea9693cacff/src/machine/stella/tia/PCMChannel.ts
|
||||
// 6502.ts (published under the MIT licence)
|
||||
// https://github.com/6502ts/6502.ts/blob/6f923e5fe693b82a2448ffac1f85aea9693cacff/src/machine/stella/tia/PCMAudio.ts
|
||||
// https://github.com/6502ts/6502.ts/blob/6f923e5fe693b82a2448ffac1f85aea9693cacff/src/machine/stella/tia/PCMChannel.ts
|
||||
//
|
||||
// Stella (published under the GNU GPL v2.0 licence)
|
||||
// https://github.com/stella-emu/stella/blob/e6af23d6c12893dd17711002971087f28f87c31f/src/emucore/tia/Audio.cxx
|
||||
// https://github.com/stella-emu/stella/blob/e6af23d6c12893dd17711002971087f28f87c31f/src/emucore/tia/AudioChannel.cxx
|
||||
// Stella (published under the GNU GPL v2.0 licence)
|
||||
// https://github.com/stella-emu/stella/blob/e6af23d6c12893dd17711002971087f28f87c31f/src/emucore/tia/Audio.cxx
|
||||
// https://github.com/stella-emu/stella/blob/e6af23d6c12893dd17711002971087f28f87c31f/src/emucore/tia/AudioChannel.cxx
|
||||
package mix
|
||||
|
||||
const maxVolume = 0x1e
|
||||
|
|
|
@ -34,10 +34,10 @@
|
|||
// The phaseclock can be "ticked" along by incrementing the integer and making
|
||||
// sure it doesn't exceed the possible values: The accepted pattern is:
|
||||
//
|
||||
// p++
|
||||
// if p >= phaseclock.NumStates {
|
||||
// p = 0
|
||||
// }
|
||||
// p++
|
||||
// if p >= phaseclock.NumStates {
|
||||
// p = 0
|
||||
// }
|
||||
//
|
||||
// Resetting and aligning the phase clock can be done by simply assigning the
|
||||
// correct value to the PhaseClock instance. Use ResetValue and AlignValue for
|
||||
|
|
|
@ -23,23 +23,23 @@
|
|||
// the TIA loop (HSYNC counter) we'd still like to know what the equivalent
|
||||
// polycounter value is. We use a 6-bit polycounter for this.
|
||||
//
|
||||
// hsync := polycounter.New(6)
|
||||
// hsync := polycounter.New(6)
|
||||
//
|
||||
// As the emulated polycounter is just an integer we can "tick" it along in the
|
||||
// obvious way. We should take care to make sure it doesn't run past the end of
|
||||
// the polycounter however. The accepted pattern is:
|
||||
//
|
||||
// p++
|
||||
// if p >= polycounter.LenTable6Bit {
|
||||
// p = 0
|
||||
// }
|
||||
// p++
|
||||
// if p >= polycounter.LenTable6Bit {
|
||||
// p = 0
|
||||
// }
|
||||
//
|
||||
// Whenever the polycounter is to be reset set it it polycounter.ResetValue.
|
||||
//
|
||||
// The polycounter bit pattern can be retrieved at any time with the ToBinary()
|
||||
// function.
|
||||
//
|
||||
// Additional Note
|
||||
// # Additional Note
|
||||
//
|
||||
// In the 2600, polycounter logic is also used to generate the bit sequences
|
||||
// required for TIA audio emulation. A real TIA variously uses 4-bit, 5-bit and
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
//
|
||||
// Adding flags is similar to the flag package. Adding a boolean flag:
|
||||
//
|
||||
// verbose := md.AddBool("verbose", false, "print additional log messages")
|
||||
// verbose := md.AddBool("verbose", false, "print additional log messages")
|
||||
//
|
||||
// These flag functions return a pointer to a variable of the specified type. The
|
||||
// initial value of these variables if the default value, the second argument in
|
||||
|
@ -132,5 +132,4 @@
|
|||
// default:
|
||||
// fmt.Printf("%s not yet implemented", md.Mode())
|
||||
// }
|
||||
//
|
||||
package modalflag
|
||||
|
|
|
@ -143,15 +143,15 @@ const (
|
|||
// Parse the top level layer of arguments. Returns a value of ParseResult.
|
||||
// The idiomatic usage is as follows:
|
||||
//
|
||||
// p, err := md.Parse()
|
||||
// switch p {
|
||||
// case modalflag.ParseHelp:
|
||||
// // help message has already been printed
|
||||
// return
|
||||
// case modalflag.ParseError:
|
||||
// printError(err)
|
||||
// return
|
||||
// }
|
||||
// p, err := md.Parse()
|
||||
// switch p {
|
||||
// case modalflag.ParseHelp:
|
||||
// // help message has already been printed
|
||||
// return
|
||||
// case modalflag.ParseError:
|
||||
// printError(err)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// Help messages are handled automatically by the function. The return value
|
||||
// ParseHelp is to help you guide your program appropriately. The above pattern
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
// that type. These values represent the different notifications that be sent
|
||||
// to the GUI.
|
||||
//
|
||||
// hardware ----> emulation ----> GUI
|
||||
// (eg. cartridge) (eg. debugger)
|
||||
// hardware ----> emulation ----> GUI
|
||||
// (eg. cartridge) (eg. debugger)
|
||||
//
|
||||
// Notifications flow in one direction only and can be generated and terminate
|
||||
// at any of the points in the chart above.
|
||||
|
|
|
@ -66,8 +66,8 @@ const (
|
|||
// NotificationHook is used for direct communication between a the hardware and
|
||||
// the emulation package. Not often used but necessary for (currently):
|
||||
//
|
||||
// . Supercharger (eg. tape start/end)
|
||||
// . PlusROM (eg. new installation)
|
||||
// . Supercharger (eg. tape start/end)
|
||||
// . PlusROM (eg. new installation)
|
||||
//
|
||||
// The emulation understands how to interpret the event and forward the
|
||||
// notification to the GUI using the gui.FeatureReq mechanism.
|
||||
|
|
34
patch/doc.go
34
patch/doc.go
|
@ -24,13 +24,13 @@
|
|||
// The first format is simplt the output of "cmp -l <old_file> <new_file>", an
|
||||
// example of which is shown below:
|
||||
//
|
||||
// 862 22 200
|
||||
// 863 360 376
|
||||
// 3713 377 242
|
||||
// 3715 377 232
|
||||
// 3716 377 114
|
||||
// 3717 377 22
|
||||
// 3718 377 360
|
||||
// 862 22 200
|
||||
// 863 360 376
|
||||
// 3713 377 242
|
||||
// 3715 377 232
|
||||
// 3716 377 114
|
||||
// 3717 377 22
|
||||
// 3718 377 360
|
||||
//
|
||||
// The first column is the offset, expressed as a decimal number and measure
|
||||
// from one. The second column is the current value of the offset being
|
||||
|
@ -47,19 +47,19 @@
|
|||
//
|
||||
// The following extract illustrates the format:
|
||||
//
|
||||
// -------------------------------------------
|
||||
// - E.T. is Not Green
|
||||
// -------------------------------------------
|
||||
// 17FA: FE FC F8 F8 F8
|
||||
// 1DE8: 04
|
||||
// -------------------------------------------
|
||||
// - E.T. is Not Green
|
||||
// -------------------------------------------
|
||||
// 17FA: FE FC F8 F8 F8
|
||||
// 1DE8: 04
|
||||
//
|
||||
// Rules:
|
||||
//
|
||||
// 1. Lines beginning with a hyphen or white space are ignored
|
||||
// 2. Offset and values are expressed in hex (case-insensitive)
|
||||
// 3. Values and offsets are separated by a colon
|
||||
// 4. Multiple values on a line are poked into consecutive offsets, starting
|
||||
// from the offset value
|
||||
// 1. Lines beginning with a hyphen or white space are ignored
|
||||
// 2. Offset and values are expressed in hex (case-insensitive)
|
||||
// 3. Values and offsets are separated by a colon
|
||||
// 4. Multiple values on a line are poked into consecutive offsets, starting
|
||||
// from the offset value
|
||||
//
|
||||
// Note that offsets are expressed with origin zero and have no relationship
|
||||
// to how memory is mapped inside the VCS. Imagine that the patches are being
|
||||
|
|
18
prefs/doc.go
18
prefs/doc.go
|
@ -41,7 +41,7 @@
|
|||
// program in the normal way. Changes can be committed to disk with the
|
||||
// Disk.Save() function and restored with Disk.Load().
|
||||
//
|
||||
//Prefs valus and Multiple Disk Instances
|
||||
// # Prefs valus and Multiple Disk Instances
|
||||
//
|
||||
// A prefs values can be added to more than one disk intance at once. Moreover,
|
||||
// more than disk instance can point to the same file on disk.
|
||||
|
@ -51,19 +51,19 @@
|
|||
// saved. Values that exist on the physical disk but which are missing from the
|
||||
// limited disk object will be preserved.
|
||||
//
|
||||
//Concurrency
|
||||
// # Concurrency
|
||||
//
|
||||
// Generally, it is safe to access a prefs value from any goroutine. However,
|
||||
// Set() should be used with care *if* SetHookPost() or SetHookPre() has been
|
||||
// set for that value.
|
||||
//
|
||||
//Command Line Support
|
||||
// # Command Line Support
|
||||
//
|
||||
// The *CommandLine*() functions are designed to help with the overriding of
|
||||
// disk values with a value given on the command line. These values are added
|
||||
// as a group with AddCommandLineGroup(). For example
|
||||
//
|
||||
// AddCommandLineGroup("foo::bar; baz::qux")
|
||||
// AddCommandLineGroup("foo::bar; baz::qux")
|
||||
//
|
||||
// (see below for more detail about the format of the prefs string)
|
||||
//
|
||||
|
@ -83,17 +83,17 @@
|
|||
//
|
||||
// For example, if the preferences file has the following entries:
|
||||
//
|
||||
// a.b.c :: 100
|
||||
// d.e.f.g :: false
|
||||
// h.i :: wibble
|
||||
// a.b.c :: 100
|
||||
// d.e.f.g :: false
|
||||
// h.i :: wibble
|
||||
//
|
||||
// A valid string to use with AddCommandLineGroup() might be:
|
||||
//
|
||||
// a.b.c::100; h.i::wibble
|
||||
// a.b.c::100; h.i::wibble
|
||||
//
|
||||
// Leading and trailing spaces around the key and value are stripped.
|
||||
//
|
||||
//Note
|
||||
// # Note
|
||||
//
|
||||
// While saved preference files are stored in UTF-8 it is not a good idea for
|
||||
// the files to be edited by hand. As such, manual editing is discorouaged with
|
||||
|
|
|
@ -27,12 +27,12 @@ import (
|
|||
//
|
||||
// Format of returned string is:
|
||||
//
|
||||
// filetype_cartname_YYYYMMDD_HHMMSS
|
||||
// filetype_cartname_YYYYMMDD_HHMMSS
|
||||
//
|
||||
// Where cartname is the string returned by cartload.ShortName(). If the
|
||||
// cartname argument is empty the returned string will be of the format:
|
||||
//
|
||||
// filetype_YYYYMMDD_HHMMSS
|
||||
// filetype_YYYYMMDD_HHMMSS
|
||||
//
|
||||
// The filetype argument is simply another way of identifying the file
|
||||
// uniquely. For example, if saving a screenshot the filetype might simply be
|
||||
|
@ -40,7 +40,7 @@ import (
|
|||
//
|
||||
// If the filetype argument is empty the returned string will be of the format:
|
||||
//
|
||||
// cartname_YYYYMMDD_HHMMSS
|
||||
// cartname_YYYYMMDD_HHMMSS
|
||||
//
|
||||
// If both filetype and cartname arguments are empty then the returned string
|
||||
// will be the timestamp only.
|
||||
|
|
|
@ -20,8 +20,8 @@ import "testing"
|
|||
// ExpectedFailure tests argument v for a failure condition suitable for it's
|
||||
// type. Currentlly support types:
|
||||
//
|
||||
// bool -> bool == false
|
||||
// error -> error != nil
|
||||
// bool -> bool == false
|
||||
// error -> error != nil
|
||||
//
|
||||
// If type is nil then the test will fail.
|
||||
func ExpectedFailure(t *testing.T, v interface{}) bool {
|
||||
|
@ -55,8 +55,8 @@ func ExpectedFailure(t *testing.T, v interface{}) bool {
|
|||
// ExpectedSuccess tests argument v for a success condition suitable for it's
|
||||
// type. Currentlly support types:
|
||||
//
|
||||
// bool -> bool == true
|
||||
// error -> error == nil
|
||||
// bool -> bool == true
|
||||
// error -> error == nil
|
||||
//
|
||||
// If type is nil then the test will succeed.
|
||||
func ExpectedSuccess(t *testing.T, v interface{}) bool {
|
||||
|
|
Loading…
Reference in a new issue