Documentation ¶
Overview ¶
Package mapper contains the CartMapper interface. This interface abstracts the functions required of any cartridge format.
In addition it defines other interfaces that a cartridge mapper may optionally implement for additional functionality for the rest of the emulation. For example, the CartHotspotBus interface can be used to reveal information about the special/hotspot addresses for a cartridge format.
In addition to the interfaces, any additional types are defined. For instance, the CartHotspotInfo type the symbol name and action type for a every hotspot in the cartridge.
Index ¶
- Constants
- type BankContent
- type BankInfo
- type CartBusStuff
- type CartCoProc
- type CartCoProcDeveloper
- type CartCoProcDisasmEntry
- type CartCoProcDisasmSummary
- type CartCoProcDisassembler
- type CartCoProcDisassemblerStdout
- type CartCoProcNonRelocatable
- type CartCoProcProfileEntry
- type CartCoProcProfiler
- type CartCoProcRelocatable
- type CartContainer
- type CartHotLoader
- type CartHotspotAction
- type CartHotspotInfo
- type CartHotspotsBus
- type CartLabels
- type CartLabelsBus
- type CartMapper
- type CartRAM
- type CartRAMbus
- type CartROMDump
- type CartRegisters
- type CartRegistersBus
- type CartRewindBoundary
- type CartStatic
- type CartStaticBus
- type CartStaticSegment
- type CartTapeBus
- type CartTapeState
- type CartYieldHook
- type CoProcState
- type OptionalSuperchip
- type PlumbFromDifferentEmulation
- type StubCartYieldHook
- type YieldReason
Constants ¶
const CartDrivenPins = 0xff
CartDrivenPins is included for clarity. In the vast majority of cases a cartridge mapper will drive all pins on the data bus during access. Use CartDrivenPins rather than 0xff.
In the case where the data bus pins are not driven a 0 will suffice.
For any cases where the databus is partially driven, the appropriate value can be used.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type BankContent ¶
type BankContent struct { // bank number Number int // copy of the bank data Data []uint8 // the segment origins that this data is allowed to be mapped to. most // cartridges will have one entry. values in the array will refer to // addresses in the cartridge address space. by convention the mappers will // refer to the primary mirror. // // memorymap.OriginCart <= origins[n] <= memorymap.MemtopCart // // to index the Data field, transform the origin and any address derived // from it, with memorymap.CartridgeBits // // idx := Origins[0] & memorymap.CartridgeBits // v := Data[idx] // // address values are supplied by the mapper implementation and must be // cartridge addresses and should in the primary cartridge mirror range // (ie. 0x1000 to 0x1fff)j Origins []uint16 }
BankContent contains data and ID of a cartridge bank. Used by CopyBanks() and helps the disassembly process.
type BankInfo ¶
type BankInfo struct { // bank number Number int // name of bank. used for special purpose banks (eg. supercharger BIOS). // should be empty if bank has no name. Name string // is cartridge memory segmented and if so which segment is this bank // mapped to IsSegmented bool Segment int // is cartridge bank writable IsRAM bool // if the address used to generate the Details is not a cartridge address. // this happens deliberately for example, during the Supercharger load // procedure, where execution happens (briefly) inside the main VCS RAM NonCart bool // the cartridge is currently feeding NOP bytes onto the data bus and // therefore the data from this bank should not be considered predictable. // // this flag has been added to support the ARM coprocessor found in // conjunction with CDF* and DPC+ mappers. future coprocessors may work // differently. ExecutingCoprocessor bool // if ExecutingCoprocessor is valid then we also record the address the // processor will resume from. CoprocessorResumeAddr uint16 }
BankInfo is used to identify a cartridge bank. In some instance a bank can be identified by it's bank number only. In other contexts more detail is required and so BankInfo is used isntead.
type CartBusStuff ¶ added in v0.19.3
CartBusStuff is implemented by cartridge mappers than can arbitrarily drive the pins on the data bus during a write.
type CartCoProc ¶ added in v0.19.3
type CartCoProc interface { CoProcID() string // set disassembler and developer hooks SetDisassembler(CartCoProcDisassembler) SetDeveloper(CartCoProcDeveloper) // the state of the coprocessor CoProcState() CoProcState // breakpoint control of coprocessor BreakpointsEnable(bool) // set interface for cartridge yields SetYieldHook(CartYieldHook) // the contents of register n. returns false if specified register is out // of range CoProcRegister(n int) (uint32, bool) CoProcRegisterSet(n int, value uint32) bool // returns the current stack frame CoProcStackFrame() uint32 // read coprocessor memory address for 8/16/32 bit values. return false if // address is out of range CoProcRead8bit(addr uint32) (uint8, bool) CoProcRead16bit(addr uint32) (uint16, bool) CoProcRead32bit(addr uint32) (uint32, bool) }
CartCoProc is implemented by cartridge mappers that have a coprocessor that functions independently from the VCS.
type CartCoProcDeveloper ¶ added in v0.16.0
type CartCoProcDeveloper interface { // addr accessed illegally by instruction at pc address. should return the // empty string if no meaningful information could be found IllegalAccess(event string, pc uint32, addr uint32) string // address is the same as the null pointer, indicating the address access // is likely to be a null pointer dereference NullAccess(event string, pc uint32, addr uint32) string // stack has collided with variable memtop StackCollision(pc uint32, sp uint32) string // returns the highest address used by the program. the coprocessor uses // this value to detect stack collisions HighAddress() uint32 // checks if address has a breakpoint assigned to it CheckBreakpoint(addr uint32) bool // returns a map that can be used to count cycles for each PC address Profiling() *CartCoProcProfiler // notifies developer that the start of a new profiling session is about to begin StartProfiling() // instructs developer implementation to accumulate profiling data. there // can be many calls to profiling profiling for every call to start // profiling ProcessProfiling() // OnYield is called whenever the ARM yields to the VCS. It communicates the PC of the most // recent instruction, the current PC (as it is now), and the reason for the yield OnYield(instructionPC uint32, currentPC uint32, reason YieldReason) }
CartCoProcDeveloper is implemented by a coprocessor to provide functions available to developers when the source code is available.
type CartCoProcDisasmEntry ¶ added in v0.8.0
CartCoProcDisasmEntry represents a single decoded instruction by the coprocessor.
type CartCoProcDisasmSummary ¶ added in v0.14.0
type CartCoProcDisasmSummary interface {
String() string
}
CartCoProcDisasmSummary represents a summary of a coprocessor execution.
type CartCoProcDisassembler ¶ added in v0.8.0
type CartCoProcDisassembler interface { // Start is called at the beginning of coprocessor program execution. Start() // Step called after every instruction in the coprocessor program. Step(CartCoProcDisasmEntry) // End is called when coprocessor program has finished. End(CartCoProcDisasmSummary) }
CartCoProcDisassembler defines the functions that must be defined for a disassembler to be attached to a coprocessor.
type CartCoProcDisassemblerStdout ¶ added in v0.8.2
type CartCoProcDisassemblerStdout struct { }
CartCoProcDisassemblerStdout is a minimial implementation of the CartCoProcDisassembler interface. It outputs entries to stdout immediately upon request.
func (*CartCoProcDisassemblerStdout) End ¶ added in v0.12.1
func (c *CartCoProcDisassemblerStdout) End(s CartCoProcDisasmSummary)
End implements the CartCoProcDisassembler interface.
func (*CartCoProcDisassemblerStdout) Start ¶ added in v0.12.1
func (c *CartCoProcDisassemblerStdout) Start()
Start implements the CartCoProcDisassembler interface.
func (*CartCoProcDisassemblerStdout) Step ¶ added in v0.12.1
func (c *CartCoProcDisassemblerStdout) Step(e CartCoProcDisasmEntry)
Instruction implements the CartCoProcDisassembler interface.
type CartCoProcNonRelocatable ¶ added in v0.20.0
type CartCoProcNonRelocatable interface {
ExecutableOrigin() uint32
}
CartCoProcNonRelocatable is implemented by cartridge mappers that are loaded into a specific coprocessor memory address.
type CartCoProcProfileEntry ¶ added in v0.19.3
type CartCoProcProfiler ¶ added in v0.19.3
type CartCoProcProfiler struct {
Entries []CartCoProcProfileEntry
}
type CartCoProcRelocatable ¶ added in v0.20.0
type CartCoProcRelocatable interface { // returns the offset of the named ELF section and whether the named // section exists. not all cartridges that implement this interface will be // able to meaningfully answer this function call ELFSection(string) ([]uint8, uint32, bool) }
CartCoProcRelocatable is implemented by cartridge mappers that are relocatable in coprocessor memory.
type CartContainer ¶
type CartContainer interface { CartMapper ContainerID() string }
CartContainer is a special CartMapper type that wraps another CartMapper. For example, the PlusROM type.
type CartHotLoader ¶ added in v0.12.1
CartHotLoader is implemented by cartridge mappers that can be hot-loaded. ie. ROM data updated but keeping RAM memory intact.
type CartHotspotAction ¶
type CartHotspotAction int
CartHotspotAction defines the action of a hotspot address.
const ( // the most common type of hotspot is the bankswitch. for these hotspots // the bank/segment is switched when the address is read/write. HotspotBankSwitch CartHotspotAction = iota // some cartridge mappers have additional registers. HotspotRegister // a function is a catch all category that describes any hotspot address // that has some other than or more complex than just bank switching. for // example, the Supercharger CONFIG address causes bank-switching to take // place but is none-the-less defined as a HotspotFunction. HotspotFunction // some hotspots will be defined but be unused or reserved by the // cartridge. HotspotReserved )
List of valid CartHotspotActions.
type CartHotspotInfo ¶
type CartHotspotInfo struct { Symbol string Action CartHotspotAction }
HotspotInfo details the name and purpose of hotspot address.
type CartHotspotsBus ¶
type CartHotspotsBus interface { ReadHotspots() map[uint16]CartHotspotInfo WriteHotspots() map[uint16]CartHotspotInfo }
CartHotspotsBus will be implemented for cartridge mappers that want to report details of any special addresses. We'll call these hotspots for all types of special addresses, not just bank switches.
The index to the returned maps, must be addresses in the cartridge address range. For normality, this should be in the primary cartridge mirror (ie. 0x1000 to 0x1fff).
type CartLabels ¶ added in v0.17.0
CartLabels is returned by CartLabelsBus. Maps addresses to symbols. Address can be any address, not just those in the cartridge.
Currently, addresses are specific and should not be mirrored.
type CartLabelsBus ¶ added in v0.17.0
type CartLabelsBus interface {
Labels() CartLabels
}
CartLabelsBus will be implemented for cartridge mappers that want to report any special labels for the cartridge type.
type CartMapper ¶
type CartMapper interface { MappedBanks() string ID() string Snapshot() CartMapper Plumb(*environment.Environment) // reset volatile areas of the cartridge. for many cartridge mappers this // will do nothing but those with registers or ram should perform an // explicit reset (possibly with randomisation) Reset() // access the cartridge at the specified address. the cartridge is expected to // drive the data bus and so this can be thought of as a "read" operation // // the mask return value allows the mapper to identify which data pins // which are being driven by the cartridge. in most cases, the mask should // be the CartDrivenPins value // // the address parameter should be normalised. ie. no mirror information Access(addr uint16, peek bool) (data uint8, mask uint8, err error) // access the cartridge at the specified volatile address. if the location // at that address is not volatile, the data value can be ignored // // we can think of this as a write operation but it will be called during a // read operation too. this is because the cartidge cannot distinguish read // and write operations and any access of a volatile address will affect it // // the address parameter should be normalised. ie. no mirror information AccessVolatile(addr uint16, data uint8, poke bool) error NumBanks() int GetBank(addr uint16) BankInfo // AccessPassive is called so that the cartridge can respond to changes to the // address and data bus even when the data bus is not addressed to the cartridge. // // see the commentary for the AccessPassive() function in the Cartridge type // for an explanation for why this is needed AccessPassive(addr uint16, data uint8) // some cartridge mappings have independent clocks that tick and change // internal cartridge state. the step() function is called every cpu cycle // at the rate specified. Step(clock float32) // patch differs from write/poke in that it alters the data as though it // was being read from disk. that is, the offset is measured from the start // of the file. the cartmapper must translate the offset and update the // correct data structure as appropriate. Patch(offset int, data uint8) error // return copies of all banks in the cartridge. the disassembly process // uses this to access cartridge data freely and without affecting the // state of the cartridge. CopyBanks() []BankContent }
CartMapper implementations hold the actual data from the loaded ROM and keeps track of which banks are mapped to individual addresses. for convenience, functions with an address argument receive that address normalised to a range of 0x0000 to 0x0fff.
type CartRAM ¶
CartRAM represents a single segment of RAM in the cartridge. A cartridge may contain more than one segment of RAM. The Label field can help distinguish between the different segments.
The Origin field specifies the address of the lowest byte in RAM. The Data field is a copy of the actual bytes in the cartidge RAM. Because Cartidge is addressable, it is also possible to update cartridge RAM through the normal memory buses; although in the context of a debugger it is probably more convience to use PutRAM() in the CartRAMbus interface.
type CartRAMbus ¶
type CartRAMbus interface { GetRAM() []CartRAM // Update the value at the index of the specified RAM bank. Note that this // is not the address; it refers to the Data array as returned by GetRAM() PutRAM(bank int, idx int, data uint8) }
CartRAMbus is implemented for catridge mappers that have an addressable RAM area. This differs from a Static area which is not addressable by the VCS.
Note that for convenience, some mappers will implement this interface but have no RAM for the specific cartridge. In these case GetRAM() will return nil.
The test for whether a specific cartridge has additional RAM should include a interface type asserstion as well as checking GetRAM() == nil.
type CartROMDump ¶ added in v0.19.3
CartROMDump is implemented by cartridge mappers that can save themselves to disk.
type CartRegisters ¶
type CartRegisters interface {
String() string
}
CartRegisters conceptualises the cartridge specific registers that are inaccessible through normal addressing.
type CartRegistersBus ¶
type CartRegistersBus interface { // GetRegisters returns a copy of the cartridge's registers GetRegisters() CartRegisters // Update a register in the cartridge with new data. // // Depending on the complexity of the cartridge, the register argument may // need to be a structured string to uniquely identify a register (eg. a // JSON string, although that's probably going over the top). The details // of what is valid should be specified in the documentation of the mappers // that use the CartRegistersbus. // // The data string will be converted to whatever type is required for the // register. For simple types then this will be usual Go representation, // (eg. true of false for boolean types) but it may be a more complex // representation. Again, the details of what is valid should be specified // in the mapper documentation. PutRegister(register string, data string) }
CartRegistersBus defines the operations required for a debugger to access any coprocessor in a cartridge.
The mapper is allowed to panic if it is not interfaced with correctly.
You should know the precise cartridge mapper for the CartRegisters to be usable.
So what's the point of the interface if you need to know the details of the underlying type? Couldn't we just use a type assertion?
Yes, but doing it this way helps with the lazy evaluation system used by debugging GUIs. The point of the lazy system is to prevent race conditions and the way we do that is to make copies of system variables before using it in the GUI. Now, because we must know the internals of the cartridge format, could we not just make those copies manually? Again, yes. But that would mean another place where the cartridge's internal knowledge needs to be coded (we need to use that knowledge in the GUI code but it would be nice to avoid it in the lazy system).
The GetRegisters() allows us to conceptualise the copying process and to keep the details inside the cartridge implementation as much as possible.
type CartRewindBoundary ¶
type CartRewindBoundary interface {
RewindBoundary() bool
}
CartRewindBoundary is implemented by cartridge mappers that require special handling from the rewind system. For some cartridge types it is not appropriate to allow rewind history to survive past a certain point.
type CartStatic ¶
type CartStatic interface { // returns a list of memory areas in the cartridge's static memory Segments() []CartStaticSegment // returns a copy of the data in the named segment. the segment name should // be taken from the Name field of one of the CartStaticSegment instances // returned by the Segments() function Reference(segment string) ([]uint8, bool) // read 8, 16 or 32 bit values from the address. the address should be in // the range given in one of the CartStaticSegment returned by the // Segments() function. Read8bit(addr uint32) (uint8, bool) Read16bit(addr uint32) (uint16, bool) Read32bit(addr uint32) (uint32, bool) }
CartStatic conceptualises a static data area that is inaccessible through the 6507.
type CartStaticBus ¶
type CartStaticBus interface { // GetStatic returns a copy of the cartridge's static areas GetStatic() CartStatic // Update the value at the index of the specified segment. the segment // argument should come from the Name field of the CartStaticSegment type // returned by CartStatic.Segments() // // The idx field should count from 0 and be no higher than the size of // memory in the segment (the differenc of Memtop and Origin returned in // the CartStaticSegment type). // // Returns false if segment is unknown or idx is out of range. // // PutStatic() will be working on the original data so PutStatic should be run // in the same goroutine as the main emulation. PutStatic(segment string, idx int, data uint8) bool }
CartStaticBus defines the operations required for a debugger to access the static memory of a cartridge.
Static memory is so called because it is inaccessible from the 6507 program. From that point of view the memory is static and can't be changed. It may however be changed by any coprocessor on the cartridge.
(Historically, the StaticBus and related types were added to support the DPC mapper type, where the memory indeed never can change. When the later cartridge mappers, DPC+ and CDF, were added the name stuck).
type CartStaticSegment ¶ added in v0.18.0
CartStaticSegment describes a single region of the underlying CartStatic memory. The Name field can be used to reference the actual memory or to update the underlying memory with CartStaticBus.PutStatic()
type CartTapeBus ¶
type CartTapeBus interface { // Move tape loading to the beginning of the tape Rewind() // Set tape counter to specified value SetTapeCounter(c int) // GetTapeState retrieves a copy of the current state of the tape. returns // true is state is valid GetTapeState() (bool, CartTapeState) }
CartTapeBus defines additional debugging functions for cartridge types that use tapes.
type CartTapeState ¶
type CartTapeState struct { Counter int MaxCounter int Time float64 MaxTime float64 Data []float32 }
CartTapeState is the current state of the tape.
type CartYieldHook ¶ added in v0.20.0
type CartYieldHook interface { // CartYield returns true if the YieldReason cannot be handled without // breaking into a debugging loop // // CartYield will return true if the cartridge mapper should cancel // coprocessing immediately // // all other yield reasons will return false CartYield(YieldReason) bool }
CartYieldHook allows a cartridge to halt execution if the cartridge coprocessor has reached a breakpoint or some other yield point (eg. undefined behaviour)
type CoProcState ¶ added in v0.19.3
type CoProcState int
CoProcState is used to describe the state of the coprocessor. We can think of these values as descriptions of the synchronisation state between the coprocessor and the VCS.
const ( // the idle state means that the coprocessor is not interacting with the // VCS at that moment. the coprocessor might be running but it is waiting // to be instructed by the VCS program CoProcIdle CoProcState = iota // a NOP feed describes the state where a cartridge mapper is waiting for // the coprocessor to finish processing. in the meantime, the cartridge is // feeding NOP instructions to the VCS CoProcNOPFeed // a StrongARM feed describes the state where the coprocessor has yielded // to the VCS in order for the next instruction to be read by the 6507 CoProcStrongARMFeed // parallel execution describes the state where the coprocessor is running // without immediate concern with VCS synchronisation CoProcParallel )
List of valid CoProcState values. A mapper will probably not employ all of these states depending on the synchronisation strategy.
In reality the state will alternate between Idle-and-NOPFeed and StronARMFeed-and-Parallel.
Other synchronisation strategies may need the addition of additional states or a different mechanism altogether.
type OptionalSuperchip ¶
type OptionalSuperchip interface { // the force argument causes the superchip to be added whether it needs it or not AddSuperchip(force bool) }
OptionalSuperchip are implemented by CartMapper implementations that require an optional superchip. This shouldn't be used to decide if a cartridge has additional RAM or not. Use the CartRAMbus interface for that.
type PlumbFromDifferentEmulation ¶ added in v0.15.0
type PlumbFromDifferentEmulation interface {
PlumbFromDifferentEmulation(*environment.Environment)
}
PlumbFromDifferentEmulation is for mappers that are sensitive to being transferred from one emulation to another.
When state is being plumbed into a different emulation to the one that has been created then this interface should be used when available, instead of the normal Plumb().
type StubCartYieldHook ¶ added in v0.20.0
type StubCartYieldHook struct{}
StubCartYieldHook is a stub implementation for the CartYieldHook interface.
func (StubCartYieldHook) CartYield ¶ added in v0.20.0
func (_ StubCartYieldHook) CartYield(_ YieldReason) bool
CartYield is a stub implementation for the CartYieldHook interface.
type YieldReason ¶ added in v0.20.0
type YieldReason string
YieldReason specifies the reason for a yield
const ( // the coprocessor has yielded because the program has ended. in this instance the // CoProcessor is not considered to be in a "yielded" state and can be modified // // Expected YieldReason for CDF and DPC+ type ROMs YieldProgramEnded YieldReason = "Program Ended" // the coprocessor has reached a synchronisation point in the program. it // must wait for the VCS before continuing // // Expected YieldReason for ACE and ELF type ROMs YieldSyncWithVCS YieldReason = "Sync With VCS" // a user supplied breakpoint has been encountered YieldBreakpoint YieldReason = "Breakpoint" // the program has triggered undefined behaviour in the coprocessor YieldUndefinedBehaviour YieldReason = "Undefined Behaviour" // the program has triggered an unimplemented feature in the coprocessor YieldUnimplementedFeature YieldReason = "Unimplemented Feature" // the program has tried to access memory illegally. details will have been // communicated by the IllegalAccess() function of the CartCoProcDeveloper // interface YieldMemoryAccessError YieldReason = "Memory Access Error" // execution error indicates that something has gone very wrong YieldExecutionError YieldReason = "Execution Error" )
List of YieldReason values