mirror of
https://github.com/JetSetIlly/Gopher2600.git
synced 2025-04-02 11:02:17 -04:00
o hardware/memory
- moved cartridge code into new package - moved bus definitions into new package o recorder - changed file-format
This commit is contained in:
parent
9e71a20847
commit
095efecd32
32 changed files with 299 additions and 303 deletions
|
@ -83,7 +83,7 @@ var commandTemplate = []string{
|
|||
cmdGrep + " %S",
|
||||
cmdHexLoad + " %N %N {%N}",
|
||||
cmdInsert + " %F",
|
||||
cmdLast + " (DEFN)",
|
||||
cmdLast + " (DEFN|BYTECODE)",
|
||||
cmdList + " [BREAKS|TRAPS|WATCHES|ALL]",
|
||||
cmdMemMap,
|
||||
cmdReflect + " (ON|OFF)",
|
||||
|
@ -587,20 +587,35 @@ func (dbg *Debugger) enactCommand(tokens *commandline.Tokens, interactive bool)
|
|||
return doNothing, nil
|
||||
|
||||
case cmdLast:
|
||||
option, ok := tokens.Get()
|
||||
if ok {
|
||||
switch strings.ToUpper(option) {
|
||||
case "DEFN":
|
||||
dbg.print(terminal.StyleFeedback, "%s", dbg.vcs.CPU.LastResult.Defn)
|
||||
}
|
||||
if dbg.vcs.CPU.LastResult.Defn == nil {
|
||||
// special condition for when LAST is called before any execution
|
||||
// has taken place
|
||||
dbg.print(terminal.StyleFeedback, "no instruction decoded yet")
|
||||
} else {
|
||||
var printTag terminal.Style
|
||||
if dbg.vcs.CPU.LastResult.Final {
|
||||
printTag = terminal.StyleCPUStep
|
||||
} else {
|
||||
printTag = terminal.StyleVideoStep
|
||||
done := false
|
||||
resultStyle := result.StyleExecution
|
||||
|
||||
option, ok := tokens.Get()
|
||||
if ok {
|
||||
switch strings.ToUpper(option) {
|
||||
case "DEFN":
|
||||
dbg.print(terminal.StyleFeedback, "%s", dbg.vcs.CPU.LastResult.Defn)
|
||||
done = true
|
||||
|
||||
case "BYTECODE":
|
||||
resultStyle = result.StyleDisasm
|
||||
}
|
||||
}
|
||||
|
||||
if !done {
|
||||
var printTag terminal.Style
|
||||
if dbg.vcs.CPU.LastResult.Final {
|
||||
printTag = terminal.StyleCPUStep
|
||||
} else {
|
||||
printTag = terminal.StyleVideoStep
|
||||
}
|
||||
dbg.print(printTag, "%s", dbg.vcs.CPU.LastResult.GetString(dbg.disasm.Symtable, resultStyle))
|
||||
}
|
||||
dbg.print(printTag, "%s", dbg.vcs.CPU.LastResult.GetString(dbg.disasm.Symtable, result.StyleExecution))
|
||||
}
|
||||
|
||||
case cmdMemMap:
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
//
|
||||
// dbg.Start(initScript, cartloader)
|
||||
//
|
||||
// The initscript is a script previously created either by the script.Scribe or
|
||||
// by hand. The cartloader argument must be an instance of cartloader. The
|
||||
// emulation proper handles the loading of the cartridge data.
|
||||
// The initscript is a script previously created either by the script.Scribe
|
||||
// package or by hand. The cartloader argument must be an instance of
|
||||
// cartloader.
|
||||
package debugger
|
||||
|
|
|
@ -5,8 +5,8 @@ import (
|
|||
"gopher2600/cartridgeloader"
|
||||
"gopher2600/errors"
|
||||
"gopher2600/hardware/cpu"
|
||||
"gopher2600/hardware/memory"
|
||||
"gopher2600/hardware/memory/addresses"
|
||||
"gopher2600/hardware/memory/cartridge"
|
||||
"gopher2600/symbols"
|
||||
"io"
|
||||
"strings"
|
||||
|
@ -18,7 +18,7 @@ type bank [disasmMask + 1]Entry
|
|||
|
||||
// Disassembly represents the annotated disassembly of a 6507 binary
|
||||
type Disassembly struct {
|
||||
cart *memory.Cartridge
|
||||
cart *cartridge.Cartridge
|
||||
|
||||
// discovered/inferred cartridge attributes
|
||||
nonCartJmps bool
|
||||
|
@ -76,7 +76,7 @@ func FromCartridge(cartload cartridgeloader.Loader) (*Disassembly, error) {
|
|||
// standard symbols table even in the event of an error
|
||||
symtable, _ := symbols.ReadSymbolsFile(cartload.Filename)
|
||||
|
||||
cart := memory.NewCartridge()
|
||||
cart := cartridge.NewCartridge()
|
||||
|
||||
err := cart.Attach(cartload)
|
||||
if err != nil {
|
||||
|
@ -93,7 +93,7 @@ func FromCartridge(cartload cartridgeloader.Loader) (*Disassembly, error) {
|
|||
|
||||
// FromMemory disassembles an existing instance of cartridge memory using a
|
||||
// cpu with no flow control.
|
||||
func FromMemory(cart *memory.Cartridge, symtable *symbols.Table) (*Disassembly, error) {
|
||||
func FromMemory(cart *cartridge.Cartridge, symtable *symbols.Table) (*Disassembly, error) {
|
||||
dsm := &Disassembly{}
|
||||
|
||||
dsm.cart = cart
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
package disassembly
|
||||
|
||||
import (
|
||||
"gopher2600/hardware/memory"
|
||||
"gopher2600/hardware/memory/cartridge"
|
||||
"gopher2600/hardware/memory/memorymap"
|
||||
)
|
||||
|
||||
// disasmMemory is a simplified memory model that allows the emulated CPU to
|
||||
// read cartridge memory.
|
||||
type disasmMemory struct {
|
||||
cart *memory.Cartridge
|
||||
cart *cartridge.Cartridge
|
||||
}
|
||||
|
||||
func (dismem *disasmMemory) Read(address uint16) (uint8, error) {
|
||||
|
|
|
@ -6,8 +6,8 @@ import (
|
|||
"gopher2600/hardware/cpu/definitions"
|
||||
"gopher2600/hardware/cpu/registers"
|
||||
"gopher2600/hardware/cpu/result"
|
||||
"gopher2600/hardware/memory"
|
||||
"gopher2600/hardware/memory/addresses"
|
||||
"gopher2600/hardware/memory/bus"
|
||||
"log"
|
||||
)
|
||||
|
||||
|
@ -27,7 +27,7 @@ type CPU struct {
|
|||
acc8 *registers.Register
|
||||
acc16 *registers.ProgramCounter
|
||||
|
||||
mem memory.CPUBus
|
||||
mem bus.CPUBus
|
||||
opCodes []*definitions.InstructionDefinition
|
||||
|
||||
// isExecuting is used for sanity checks - to make sure we're not calling CPU
|
||||
|
@ -59,7 +59,7 @@ type CPU struct {
|
|||
}
|
||||
|
||||
// NewCPU is the preferred method of initialisation for the CPU structure
|
||||
func NewCPU(mem memory.CPUBus) (*CPU, error) {
|
||||
func NewCPU(mem bus.CPUBus) (*CPU, error) {
|
||||
mc := &CPU{mem: mem}
|
||||
|
||||
mc.PC = registers.NewProgramCounter(0)
|
||||
|
|
|
@ -126,14 +126,14 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
// Named TIA registers
|
||||
// TIA registers
|
||||
//
|
||||
// These value are used by the emulator to specifiy known addresses. For
|
||||
// example, when writing collision information we know we need the CXM0P
|
||||
// register. these named values make the code more readable
|
||||
//
|
||||
// For simplicity values are enumerated from 0; value is added to the origin
|
||||
// address of the TIA in ChipBus.ChipWrite implementation
|
||||
// Values are enumerated from 0; value is added to the origin address of the
|
||||
// TIA in ChipBus.ChipWrite implementation
|
||||
const (
|
||||
CXM0P uint16 = iota
|
||||
CXM1P
|
||||
|
@ -151,14 +151,14 @@ const (
|
|||
INPT5
|
||||
)
|
||||
|
||||
// Named RIOT registers
|
||||
// RIOT registers
|
||||
//
|
||||
// These value are used by the emulator to specifiy known addresses. For
|
||||
// example, the timer updates itself every cycle and stores time remaining
|
||||
// value in the INTIM register.
|
||||
//
|
||||
// For simplicity values are enumerated from 0; value is added to the origin
|
||||
// address of the TIA in ChipBus.ChipWrite implementation
|
||||
// Values are enumerated from 0; value is added to the origin address of the
|
||||
// TIA in ChipBus.ChipWrite implementation
|
||||
const (
|
||||
SWCHA uint16 = iota
|
||||
SWACNT
|
||||
|
|
|
@ -10,9 +10,11 @@
|
|||
// is noticeably slower than accessing a sparse array. There is probably no
|
||||
// need to use this arrays outside of the emulation code.
|
||||
//
|
||||
// The Named TIA and RIOT registers probably don't need referring to outside
|
||||
// the emulation code.
|
||||
// "TIA Registers" and "RIOT Registers" are so named because to those areas,
|
||||
// those addresses look like registers. They probably don't need referring to
|
||||
// outside the emulation code.
|
||||
//
|
||||
// DataMasks help implement VCS data/address bus artefacts and probably don't
|
||||
// need to be referred to outside the emulation code.
|
||||
// DataMasks help implement VCS data/address bus artefacts (fully explained
|
||||
// beloew) and probably don't need to be referred to outside the emulation
|
||||
// code.
|
||||
package addresses
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
package memory
|
||||
// Package bus defines the memory bus concept. For an explanation see the
|
||||
// memory package documentation.
|
||||
package bus
|
||||
|
||||
// CPUBus defines the operations for the memory system when accessed from the CPU
|
||||
// All memory areas implement this interface because they are all accessible
|
28
hardware/memory/cartridge/cartmapper.go
Normal file
28
hardware/memory/cartridge/cartmapper.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package cartridge
|
||||
|
||||
// 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 recieve that address
|
||||
// normalised to a range of 0x0000 to 0x0fff
|
||||
type cartMapper interface {
|
||||
initialise()
|
||||
read(addr uint16) (data uint8, err error)
|
||||
write(addr uint16, data uint8) error
|
||||
numBanks() int
|
||||
getBank(addr uint16) (bank int)
|
||||
setBank(addr uint16, bank int) error
|
||||
saveState() interface{}
|
||||
restoreState(interface{}) error
|
||||
ram() []uint8
|
||||
|
||||
// tigervision cartridges have a very wierd bank-switching method that
|
||||
// require a way of notifying the cartridge of writes to addresses outside
|
||||
// of cartridge space
|
||||
listen(addr uint16, data uint8)
|
||||
}
|
||||
|
||||
// optionalSuperchip are implemented by cartMappers that have an optional
|
||||
// superchip
|
||||
type optionalSuperchip interface {
|
||||
addSuperchip() bool
|
||||
}
|
|
@ -1,74 +1,33 @@
|
|||
package memory
|
||||
package cartridge
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"gopher2600/cartridgeloader"
|
||||
"gopher2600/errors"
|
||||
"gopher2600/hardware/memory/bus"
|
||||
"gopher2600/hardware/memory/memorymap"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 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 recieve that address
|
||||
// normalised to a range of 0x0000 to 0x0fff
|
||||
type cartMapper interface {
|
||||
initialise()
|
||||
read(addr uint16) (data uint8, err error)
|
||||
write(addr uint16, data uint8) error
|
||||
numBanks() int
|
||||
getBank(addr uint16) (bank int)
|
||||
setBank(addr uint16, bank int) error
|
||||
saveState() interface{}
|
||||
restoreState(interface{}) error
|
||||
ram() []uint8
|
||||
|
||||
// listen differs from write in that the address is the unmapped address on
|
||||
// the address bus. for convenience, memory functions deal with addresses
|
||||
// that have been mapped and normalised so they count from zero.
|
||||
// cartMapper.listen() is the exception.
|
||||
listen(addr uint16, data uint8) error
|
||||
}
|
||||
|
||||
// optionalSuperchip are implemented by cartMappers that have an optional
|
||||
// superchip
|
||||
type optionalSuperchip interface {
|
||||
addSuperchip() bool
|
||||
}
|
||||
|
||||
// Cartridge defines the information and operations for a VCS cartridge
|
||||
type Cartridge struct {
|
||||
DebuggerBus
|
||||
CPUBus
|
||||
bus.DebuggerBus
|
||||
bus.CPUBus
|
||||
|
||||
origin uint16
|
||||
memtop uint16
|
||||
|
||||
// full path to the cartridge as stored on disk
|
||||
Filename string
|
||||
|
||||
// the format requested by the CartridgeLoader
|
||||
RequestedFormat string
|
||||
|
||||
// hash of binary loaded from disk. any subsequent pokes to cartridge
|
||||
// memory will not be reflected in the value
|
||||
Hash string
|
||||
Hash string
|
||||
|
||||
// the specific cartridge data, mapped appropriately to the memory
|
||||
// interfaces
|
||||
mapper cartMapper
|
||||
}
|
||||
|
||||
// NewCartridge is the preferred method of initialisation for the cartridges
|
||||
// NewCartridge is the preferred method of initialisation for the cartridge
|
||||
// type
|
||||
func NewCartridge() *Cartridge {
|
||||
cart := &Cartridge{
|
||||
origin: memorymap.OriginCart,
|
||||
memtop: memorymap.MemtopCart,
|
||||
}
|
||||
|
||||
cart := &Cartridge{}
|
||||
cart.Eject()
|
||||
|
||||
return cart
|
||||
}
|
||||
|
||||
|
@ -78,7 +37,7 @@ func (cart Cartridge) String() string {
|
|||
|
||||
// Peek is an implementation of memory.DebuggerBus
|
||||
func (cart Cartridge) Peek(addr uint16) (uint8, error) {
|
||||
addr &= cart.origin - 1
|
||||
addr &= memorymap.OriginCart - 1
|
||||
return cart.mapper.read(addr)
|
||||
}
|
||||
|
||||
|
@ -90,13 +49,13 @@ func (cart Cartridge) Poke(addr uint16, data uint8) error {
|
|||
// Read is an implementation of memory.CPUBus
|
||||
// * optimisation: called a lot. pointer to Cartridge to prevent duffcopy
|
||||
func (cart *Cartridge) Read(addr uint16) (uint8, error) {
|
||||
addr &= cart.origin - 1
|
||||
addr &= memorymap.OriginCart - 1
|
||||
return cart.mapper.read(addr)
|
||||
}
|
||||
|
||||
// Write is an implementation of memory.CPUBus
|
||||
func (cart *Cartridge) Write(addr uint16, data uint8) error {
|
||||
addr &= cart.origin - 1
|
||||
addr &= memorymap.OriginCart - 1
|
||||
return cart.mapper.write(addr, data)
|
||||
}
|
||||
|
||||
|
@ -108,86 +67,6 @@ func (cart *Cartridge) Eject() {
|
|||
cart.mapper = newEjected()
|
||||
}
|
||||
|
||||
// fingerprint8k attempts a divination of 8k cartridge data and decide on a
|
||||
// suitable cartMapper implementation
|
||||
func (cart Cartridge) fingerprint8k(data []byte) func([]byte) (cartMapper, error) {
|
||||
if fingerprintTigervision(data) {
|
||||
return newTigervision
|
||||
}
|
||||
|
||||
if fingerprintParkerBros(data) {
|
||||
return newparkerBros
|
||||
}
|
||||
|
||||
return newAtari8k
|
||||
}
|
||||
|
||||
// fingerprint16k attempts a divination of 16k cartridge data and decide on a
|
||||
// suitable cartMapper implementation
|
||||
func (cart Cartridge) fingerprint16k(data []byte) func([]byte) (cartMapper, error) {
|
||||
if fingerprintMnetwork(data) {
|
||||
return newMnetwork
|
||||
}
|
||||
|
||||
return newAtari16k
|
||||
}
|
||||
|
||||
func (cart *Cartridge) fingerprint(data []byte) error {
|
||||
var err error
|
||||
|
||||
switch len(data) {
|
||||
case 2048:
|
||||
cart.mapper, err = newAtari2k(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case 4096:
|
||||
cart.mapper, err = newAtari4k(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case 8192:
|
||||
cart.mapper, err = cart.fingerprint8k(data)(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case 12288:
|
||||
cart.mapper, err = newCBS(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case 16384:
|
||||
cart.mapper, err = cart.fingerprint16k(data)(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case 32768:
|
||||
cart.mapper, err = newAtari32k(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case 65536:
|
||||
return errors.New(errors.CartridgeError, "65536 bytes not yet supported")
|
||||
|
||||
default:
|
||||
return errors.New(errors.CartridgeError, fmt.Sprintf("unrecognised cartridge size (%d bytes)", len(data)))
|
||||
}
|
||||
|
||||
// if cartridge mapper implements the optionalSuperChip interface then try
|
||||
// to add the additional RAM
|
||||
if superchip, ok := cart.mapper.(optionalSuperchip); ok {
|
||||
superchip.addSuperchip()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsEjected returns true if no cartridge is attached
|
||||
func (cart *Cartridge) IsEjected() bool {
|
||||
return cart.Hash == ejectedHash
|
||||
|
@ -203,7 +82,6 @@ func (cart *Cartridge) Attach(cartload cartridgeloader.Loader) error {
|
|||
|
||||
// note name of cartridge
|
||||
cart.Filename = cartload.Filename
|
||||
cart.RequestedFormat = cartload.Format
|
||||
cart.mapper = newEjected()
|
||||
|
||||
// generate hash
|
||||
|
@ -293,7 +171,7 @@ func (cart Cartridge) NumBanks() int {
|
|||
|
||||
// GetBank returns the current bank number for the specified address
|
||||
func (cart Cartridge) GetBank(addr uint16) int {
|
||||
addr &= cart.origin - 1
|
||||
addr &= memorymap.OriginCart - 1
|
||||
return cart.mapper.getBank(addr)
|
||||
}
|
||||
|
||||
|
@ -301,7 +179,7 @@ func (cart Cartridge) GetBank(addr uint16) int {
|
|||
// bank. For many cart mappers this just means switching banks for the entire
|
||||
// cartridge
|
||||
func (cart *Cartridge) SetBank(addr uint16, bank int) error {
|
||||
addr &= cart.origin - 1
|
||||
addr &= memorymap.OriginCart - 1
|
||||
return cart.mapper.setBank(addr, bank)
|
||||
}
|
||||
|
||||
|
@ -321,9 +199,9 @@ func (cart Cartridge) RAM() []uint8 {
|
|||
return cart.mapper.ram()
|
||||
}
|
||||
|
||||
// Listen for data at the specified address. return CartridgeListen error if
|
||||
// nothing was done with the information. Callers to Listen() will probably
|
||||
// want to filter out that error.
|
||||
func (cart Cartridge) Listen(addr uint16, data uint8) error {
|
||||
return cart.mapper.listen(addr, data)
|
||||
// Listen for data at the specified address. very wierd requirement of the
|
||||
// tigervision cartridge format. If there was a better way of implementing the
|
||||
// tigervision format, there'd be no need for this function.
|
||||
func (cart Cartridge) Listen(addr uint16, data uint8) {
|
||||
cart.mapper.listen(addr, data)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package memory
|
||||
package cartridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -146,8 +146,7 @@ func (cart atari) ram() []uint8 {
|
|||
return cart.superchip
|
||||
}
|
||||
|
||||
func (cart atari) listen(addr uint16, data uint8) error {
|
||||
return nil
|
||||
func (cart atari) listen(addr uint16, data uint8) {
|
||||
}
|
||||
|
||||
// atari4k is the original and most straightforward format
|
|
@ -1,4 +1,4 @@
|
|||
package memory
|
||||
package cartridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -126,6 +126,5 @@ func (cart cbs) ram() []uint8 {
|
|||
return cart.superchip
|
||||
}
|
||||
|
||||
func (cart cbs) listen(addr uint16, data uint8) error {
|
||||
return nil
|
||||
func (cart cbs) listen(addr uint16, data uint8) {
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package memory
|
||||
package cartridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -60,6 +60,5 @@ func (cart ejected) ram() []uint8 {
|
|||
return []uint8{}
|
||||
}
|
||||
|
||||
func (cart ejected) listen(addr uint16, data uint8) error {
|
||||
return nil
|
||||
func (cart ejected) listen(addr uint16, data uint8) {
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package memory
|
||||
package cartridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -188,7 +188,7 @@ func (cart *mnetwork) bankSwitchOnAccess(addr uint16) bool {
|
|||
case 0x0fe7:
|
||||
cart.lowerSegment = 7
|
||||
|
||||
// from bankswitch_size.txt: "You select which 256 byte block appears
|
||||
// from bankswitch_sizes.txt: "You select which 256 byte block appears
|
||||
// here by accessing 1FF8 to 1FFB."
|
||||
//
|
||||
// "here" refers to the read range 0x0900 to 0x09ff and the write range
|
||||
|
@ -272,6 +272,5 @@ func (cart *mnetwork) ram() []uint8 {
|
|||
return mem
|
||||
}
|
||||
|
||||
func (cart *mnetwork) listen(addr uint16, data uint8) error {
|
||||
return nil
|
||||
func (cart *mnetwork) listen(addr uint16, data uint8) {
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package memory
|
||||
package cartridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -219,6 +219,5 @@ func (cart parkerBros) ram() []uint8 {
|
|||
return []uint8{}
|
||||
}
|
||||
|
||||
func (cart parkerBros) listen(addr uint16, data uint8) error {
|
||||
return nil
|
||||
func (cart parkerBros) listen(addr uint16, data uint8) {
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package memory
|
||||
package cartridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -136,17 +136,22 @@ func (cart *tigervision) ram() []uint8 {
|
|||
return []uint8{}
|
||||
}
|
||||
|
||||
func (cart *tigervision) listen(addr uint16, data uint8) error {
|
||||
// tigervision is seemingly unique in that in bank-switches when an address
|
||||
func (cart *tigervision) listen(addr uint16, data uint8) {
|
||||
// tigervision is seemingly unique in that it bank switches when an address
|
||||
// outside of cartridge space is written to. for this to work, we need the
|
||||
// listen() function.
|
||||
|
||||
// althought address 3F is used primarily for bank switching in actual
|
||||
// fact writing anywhere in TIA space is okay
|
||||
// although address 3F is used primarily, in actual fact writing anywhere
|
||||
// in TIA space is okay. from the description from Kevin Horton's document
|
||||
// (quoted above) whenever an address in TIA space is written to, the lower
|
||||
// 3 bits of the value being written is used to set the segment.
|
||||
|
||||
if addr < 0x40 {
|
||||
// only the lowest three bits of the data value are used
|
||||
cart.segment[0] = int(data & 0x03)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
|
||||
// this bank switching method causes a problem when the CPU wants to write
|
||||
// to TIA space for real and not cause a bankswitch. for this reason,
|
||||
// tigervision cartridges use mirror addresses to write to the TIA.
|
||||
}
|
22
hardware/memory/cartridge/doc.go
Normal file
22
hardware/memory/cartridge/doc.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Package cartridge fully implements loading of mapping of cartridge memory.
|
||||
//
|
||||
// There are many different types of cartridge most of which are supported by
|
||||
// the package. Some cartridge types contain additional RAM but the main
|
||||
// difference is how they map additional ROM to the relatively small address
|
||||
// space available for cartridges in the VCS. This is called bank-switching.
|
||||
// All of these differences are handled transparently by the package.
|
||||
//
|
||||
// Currently supported cartridge types are:
|
||||
//
|
||||
// - Atari 2k / 4k / 8k / 16k and 32k
|
||||
//
|
||||
// - the above with additional Superchip (additional RAM in other words)
|
||||
//
|
||||
// - Parker Bros.
|
||||
//
|
||||
// - MNetwork
|
||||
//
|
||||
// - Tigervision
|
||||
//
|
||||
// - CBS
|
||||
package cartridge
|
82
hardware/memory/cartridge/fingerprint.go
Normal file
82
hardware/memory/cartridge/fingerprint.go
Normal file
|
@ -0,0 +1,82 @@
|
|||
package cartridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gopher2600/errors"
|
||||
)
|
||||
|
||||
func (cart Cartridge) fingerprint8k(data []byte) func([]byte) (cartMapper, error) {
|
||||
if fingerprintTigervision(data) {
|
||||
return newTigervision
|
||||
}
|
||||
|
||||
if fingerprintParkerBros(data) {
|
||||
return newparkerBros
|
||||
}
|
||||
|
||||
return newAtari8k
|
||||
}
|
||||
|
||||
func (cart Cartridge) fingerprint16k(data []byte) func([]byte) (cartMapper, error) {
|
||||
if fingerprintMnetwork(data) {
|
||||
return newMnetwork
|
||||
}
|
||||
|
||||
return newAtari16k
|
||||
}
|
||||
|
||||
func (cart *Cartridge) fingerprint(data []byte) error {
|
||||
var err error
|
||||
|
||||
switch len(data) {
|
||||
case 2048:
|
||||
cart.mapper, err = newAtari2k(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case 4096:
|
||||
cart.mapper, err = newAtari4k(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case 8192:
|
||||
cart.mapper, err = cart.fingerprint8k(data)(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case 12288:
|
||||
cart.mapper, err = newCBS(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case 16384:
|
||||
cart.mapper, err = cart.fingerprint16k(data)(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case 32768:
|
||||
cart.mapper, err = newAtari32k(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case 65536:
|
||||
return errors.New(errors.CartridgeError, "65536 bytes not yet supported")
|
||||
|
||||
default:
|
||||
return errors.New(errors.CartridgeError, fmt.Sprintf("unrecognised cartridge size (%d bytes)", len(data)))
|
||||
}
|
||||
|
||||
// if cartridge mapper implements the optionalSuperChip interface then try
|
||||
// to add the additional RAM
|
||||
if superchip, ok := cart.mapper.(optionalSuperchip); ok {
|
||||
superchip.addSuperchip()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -4,18 +4,23 @@ import (
|
|||
"fmt"
|
||||
"gopher2600/errors"
|
||||
"gopher2600/hardware/memory/addresses"
|
||||
"gopher2600/hardware/memory/bus"
|
||||
)
|
||||
|
||||
// ChipMemory defines the information for and operations allowed for those
|
||||
// memory areas accessed by the VCS chips as well as the CPU
|
||||
type ChipMemory struct {
|
||||
DebuggerBus
|
||||
ChipBus
|
||||
CPUBus
|
||||
PeriphBus
|
||||
bus.DebuggerBus
|
||||
bus.ChipBus
|
||||
bus.CPUBus
|
||||
bus.PeriphBus
|
||||
|
||||
// because we're servicing two different memory areas with this type, we
|
||||
// need to store the origin and memtop values here, rather than using the
|
||||
// constants from the memorymap package directly
|
||||
origin uint16
|
||||
memtop uint16
|
||||
|
||||
memory []uint8
|
||||
|
||||
// additional mask to further reduce address space when read from the CPU
|
||||
|
@ -49,13 +54,13 @@ func (area ChipMemory) Poke(address uint16, value uint8) error {
|
|||
}
|
||||
|
||||
// ChipRead is an implementation of memory.ChipBus
|
||||
func (area *ChipMemory) ChipRead() (bool, ChipData) {
|
||||
func (area *ChipMemory) ChipRead() (bool, bus.ChipData) {
|
||||
if area.writeSignal {
|
||||
area.writeSignal = false
|
||||
return true, ChipData{Name: addresses.Write[area.lastWriteAddress], Value: area.writeData}
|
||||
return true, bus.ChipData{Name: addresses.Write[area.lastWriteAddress], Value: area.writeData}
|
||||
}
|
||||
|
||||
return false, ChipData{}
|
||||
return false, bus.ChipData{}
|
||||
}
|
||||
|
||||
// ChipWrite is an implementation of memory.ChipBus
|
||||
|
|
|
@ -57,32 +57,6 @@
|
|||
//
|
||||
// The arrow pointing away from the Cartridge area indicates that the CPU can
|
||||
// only read from the cartridge, it cannot write to it. Unless that is, the
|
||||
// cartridge has internal RAM. The differences in cartridge abilities in this
|
||||
// regard is handled by the cartMapper interface.
|
||||
//
|
||||
// The cartMapper interface allows the transparent implementation of the
|
||||
// different cartridge formats that have been used by the VCS. We've already
|
||||
// mentioned cartridge RAM but the major difference betwen cartridge types is
|
||||
// how they handle so-called bank-switching.
|
||||
//
|
||||
// The differences between the cartridge types is too much to go into here but
|
||||
// a good reference for this can be found here:
|
||||
//
|
||||
// http://blog.kevtris.org/blogfiles/Atari%202600%20Mappers.txt
|
||||
//
|
||||
// Currently supported cartridge types are:
|
||||
//
|
||||
// - Atari 2k / 4k / 8k / 16k and 32k
|
||||
//
|
||||
// - the above with additional Superchip (additional RAM in other words)
|
||||
//
|
||||
// - Parker Bros.
|
||||
//
|
||||
// - MNetwork
|
||||
//
|
||||
// - Tigervision
|
||||
//
|
||||
// - CBS
|
||||
//
|
||||
// Other cartridge types can easily be added using the cartMapper system.
|
||||
// cartridge has internal RAM. See the cartridge package documentation for the
|
||||
// discussion on this.
|
||||
package memory
|
||||
|
|
|
@ -3,22 +3,24 @@ package memory
|
|||
import (
|
||||
"gopher2600/errors"
|
||||
"gopher2600/hardware/memory/addresses"
|
||||
"gopher2600/hardware/memory/bus"
|
||||
"gopher2600/hardware/memory/cartridge"
|
||||
"gopher2600/hardware/memory/memorymap"
|
||||
)
|
||||
|
||||
// VCSMemory is the monolithic representation of the memory in 2600.
|
||||
type VCSMemory struct {
|
||||
CPUBus
|
||||
bus.CPUBus
|
||||
|
||||
// memmap is a hash for every address in the VCS address space, returning
|
||||
// one of the four memory areas
|
||||
Memmap []DebuggerBus
|
||||
Memmap []bus.DebuggerBus
|
||||
|
||||
// the four memory areas
|
||||
RIOT *ChipMemory
|
||||
TIA *ChipMemory
|
||||
PIA *PIA
|
||||
Cart *Cartridge
|
||||
Cart *cartridge.Cartridge
|
||||
|
||||
// the following are only used by the debugging interface. it would be
|
||||
// lovely to remove these for non-debugging emulation but there's not much
|
||||
|
@ -46,12 +48,12 @@ type VCSMemory struct {
|
|||
func NewVCSMemory() (*VCSMemory, error) {
|
||||
mem := &VCSMemory{}
|
||||
|
||||
mem.Memmap = make([]DebuggerBus, memorymap.Memtop+1)
|
||||
mem.Memmap = make([]bus.DebuggerBus, memorymap.Memtop+1)
|
||||
|
||||
mem.RIOT = newRIOT()
|
||||
mem.TIA = newTIA()
|
||||
mem.PIA = newPIA()
|
||||
mem.Cart = NewCartridge()
|
||||
mem.Cart = cartridge.NewCartridge()
|
||||
|
||||
if mem.RIOT == nil || mem.TIA == nil || mem.PIA == nil || mem.Cart == nil {
|
||||
return nil, errors.New(errors.MemoryError, "cannot create memory areas")
|
||||
|
@ -59,19 +61,19 @@ func NewVCSMemory() (*VCSMemory, error) {
|
|||
|
||||
// create the memory map by associating all addresses in each memory area
|
||||
// with that area
|
||||
for i := mem.TIA.origin; i <= mem.TIA.memtop; i++ {
|
||||
for i := memorymap.OriginTIA; i <= memorymap.MemtopTIA; i++ {
|
||||
mem.Memmap[i] = mem.TIA
|
||||
}
|
||||
|
||||
for i := mem.PIA.origin; i <= mem.PIA.memtop; i++ {
|
||||
for i := memorymap.OriginPIA; i <= memorymap.MemtopPIA; i++ {
|
||||
mem.Memmap[i] = mem.PIA
|
||||
}
|
||||
|
||||
for i := mem.RIOT.origin; i <= mem.RIOT.memtop; i++ {
|
||||
for i := memorymap.OriginRIOT; i <= memorymap.MemtopRIOT; i++ {
|
||||
mem.Memmap[i] = mem.RIOT
|
||||
}
|
||||
|
||||
for i := mem.Cart.origin; i <= mem.Cart.memtop; i++ {
|
||||
for i := memorymap.OriginCart; i <= memorymap.MemtopCart; i++ {
|
||||
mem.Memmap[i] = mem.Cart
|
||||
}
|
||||
|
||||
|
@ -79,7 +81,7 @@ func NewVCSMemory() (*VCSMemory, error) {
|
|||
}
|
||||
|
||||
// GetArea returns the actual memory of the specified area type
|
||||
func (mem *VCSMemory) GetArea(area memorymap.Area) (DebuggerBus, error) {
|
||||
func (mem *VCSMemory) GetArea(area memorymap.Area) (bus.DebuggerBus, error) {
|
||||
switch area {
|
||||
case memorymap.TIA:
|
||||
return mem.TIA, nil
|
||||
|
@ -104,7 +106,7 @@ func (mem *VCSMemory) Read(address uint16) (uint8, error) {
|
|||
return 0, err
|
||||
}
|
||||
|
||||
data, err := area.(CPUBus).Read(ma)
|
||||
data, err := area.(bus.CPUBus).Read(ma)
|
||||
|
||||
// some memory areas do not change all the bits on the data bus, leaving
|
||||
// some bits of the address in the result
|
||||
|
@ -147,19 +149,11 @@ func (mem *VCSMemory) Write(address uint16, data uint8) error {
|
|||
mem.LastAccessID = mem.accessCount
|
||||
mem.accessCount++
|
||||
|
||||
// as incredible as it may seem some cartridges react to memory writes to
|
||||
// addresses not in the cartridge space. for example, tigervision
|
||||
// cartridges switch banks whenever any (non-mapped) address in the range
|
||||
// 0x00 to 0x3f is written to.
|
||||
err = mem.Cart.Listen(address, data)
|
||||
// as incredible as it may seem tigervision cartridges react to memory
|
||||
// writes to (unmapped) addresses in the range 0x00 to 0x3f. the Listen()
|
||||
// function is a horrible solution to this but I can't see how else to
|
||||
// handle it.
|
||||
mem.Cart.Listen(address, data)
|
||||
|
||||
// the only error we expect from the cartMapper is and UnwritableAddress
|
||||
// error, which most cartridge types will respond with in all circumstances
|
||||
if err != nil {
|
||||
if _, ok := err.(errors.AtariError); !ok {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return area.(CPUBus).Write(ma, data)
|
||||
return area.(bus.CPUBus).Write(ma, data)
|
||||
}
|
||||
|
|
|
@ -2,14 +2,15 @@ package memory
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"gopher2600/hardware/memory/bus"
|
||||
"gopher2600/hardware/memory/memorymap"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PIA defines the information for and operation allowed for PIA PIA
|
||||
type PIA struct {
|
||||
DebuggerBus
|
||||
CPUBus
|
||||
bus.DebuggerBus
|
||||
bus.CPUBus
|
||||
|
||||
origin uint16
|
||||
memtop uint16
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
// Panel uses the concurrent chip bus interface
|
||||
|
||||
package peripherals
|
||||
|
||||
import (
|
||||
"gopher2600/errors"
|
||||
"gopher2600/hardware/memory"
|
||||
"gopher2600/hardware/memory/addresses"
|
||||
"gopher2600/hardware/memory/bus"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -15,7 +13,7 @@ type Panel struct {
|
|||
|
||||
id PeriphID
|
||||
|
||||
riot memory.PeriphBus
|
||||
riot bus.PeriphBus
|
||||
p0pro bool
|
||||
p1pro bool
|
||||
color bool
|
||||
|
@ -24,7 +22,7 @@ type Panel struct {
|
|||
}
|
||||
|
||||
// NewPanel is the preferred method of initialisation for the Panel type
|
||||
func NewPanel(riot memory.PeriphBus) *Panel {
|
||||
func NewPanel(riot bus.PeriphBus) *Panel {
|
||||
pan := &Panel{
|
||||
id: PanelID,
|
||||
riot: riot,
|
||||
|
|
|
@ -2,8 +2,8 @@ package peripherals
|
|||
|
||||
import (
|
||||
"gopher2600/errors"
|
||||
"gopher2600/hardware/memory"
|
||||
"gopher2600/hardware/memory/addresses"
|
||||
"gopher2600/hardware/memory/bus"
|
||||
)
|
||||
|
||||
// Ports is the containing structure for the two player ports
|
||||
|
@ -13,7 +13,7 @@ type Ports struct {
|
|||
}
|
||||
|
||||
// NewPorts is the preferred method of initialisation for the Ports type
|
||||
func NewPorts(riot memory.PeriphBus, tia memory.PeriphBus, panel *Panel) *Ports {
|
||||
func NewPorts(riot bus.PeriphBus, tia bus.PeriphBus, panel *Panel) *Ports {
|
||||
return &Ports{
|
||||
Player0: newPlayer0(riot, tia, panel),
|
||||
Player1: newPlayer1(riot, tia, panel),
|
||||
|
@ -26,8 +26,8 @@ type player struct {
|
|||
|
||||
id PeriphID
|
||||
|
||||
riot memory.PeriphBus
|
||||
tia memory.PeriphBus
|
||||
riot bus.PeriphBus
|
||||
tia bus.PeriphBus
|
||||
panel *Panel
|
||||
|
||||
// joystick
|
||||
|
@ -48,7 +48,7 @@ type player struct {
|
|||
buttonMask uint8
|
||||
}
|
||||
|
||||
func newPlayer0(riot memory.PeriphBus, tia memory.PeriphBus, panel *Panel) *player {
|
||||
func newPlayer0(riot bus.PeriphBus, tia bus.PeriphBus, panel *Panel) *player {
|
||||
pl := &player{
|
||||
id: PlayerZeroID,
|
||||
riot: riot,
|
||||
|
@ -71,7 +71,7 @@ func newPlayer0(riot memory.PeriphBus, tia memory.PeriphBus, panel *Panel) *play
|
|||
return pl
|
||||
}
|
||||
|
||||
func newPlayer1(riot memory.PeriphBus, tia memory.PeriphBus, panel *Panel) *player {
|
||||
func newPlayer1(riot bus.PeriphBus, tia bus.PeriphBus, panel *Panel) *player {
|
||||
pl := &player{
|
||||
id: PlayerOneID,
|
||||
riot: riot,
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
package riot
|
||||
|
||||
import (
|
||||
"gopher2600/hardware/memory"
|
||||
"gopher2600/hardware/memory/bus"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RIOT contains all the sub-components of the VCS RIOT sub-system
|
||||
type RIOT struct {
|
||||
mem memory.ChipBus
|
||||
mem bus.ChipBus
|
||||
|
||||
Timer *timer
|
||||
}
|
||||
|
||||
// NewRIOT creates a RIOT, to be used in a VCS emulation
|
||||
func NewRIOT(mem memory.ChipBus) *RIOT {
|
||||
func NewRIOT(mem bus.ChipBus) *RIOT {
|
||||
riot := &RIOT{mem: mem}
|
||||
riot.Timer = newTimer(mem)
|
||||
|
||||
|
|
|
@ -2,12 +2,12 @@ package riot
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"gopher2600/hardware/memory"
|
||||
"gopher2600/hardware/memory/addresses"
|
||||
"gopher2600/hardware/memory/bus"
|
||||
)
|
||||
|
||||
type timer struct {
|
||||
mem memory.ChipBus
|
||||
mem bus.ChipBus
|
||||
|
||||
// register is the name of the currently selected RIOT timer
|
||||
register string
|
||||
|
@ -45,7 +45,7 @@ type timer struct {
|
|||
cyclesElapsed int
|
||||
}
|
||||
|
||||
func newTimer(mem memory.ChipBus) *timer {
|
||||
func newTimer(mem bus.ChipBus) *timer {
|
||||
tmr := &timer{
|
||||
mem: mem,
|
||||
register: "TIM1024",
|
||||
|
@ -71,7 +71,7 @@ func (tmr timer) String() string {
|
|||
)
|
||||
}
|
||||
|
||||
func (tmr *timer) serviceMemory(data memory.ChipData) bool {
|
||||
func (tmr *timer) serviceMemory(data bus.ChipData) bool {
|
||||
switch data.Name {
|
||||
case "TIM1T":
|
||||
tmr.register = data.Name
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
package audio
|
||||
|
||||
import (
|
||||
"gopher2600/hardware/memory"
|
||||
)
|
||||
import "gopher2600/hardware/memory/bus"
|
||||
|
||||
// UpdateRegisters checks the TIA memory for changes to registers that are
|
||||
// interesting to the audio sub-system
|
||||
//
|
||||
// Returns true if memory.ChipData has not been serviced.
|
||||
func (au *Audio) UpdateRegisters(data memory.ChipData) bool {
|
||||
func (au *Audio) UpdateRegisters(data bus.ChipData) bool {
|
||||
switch data.Name {
|
||||
case "AUDC0":
|
||||
au.channel0.regControl = data.Value & 0x0f
|
||||
|
|
|
@ -2,7 +2,7 @@ package tia
|
|||
|
||||
import (
|
||||
"gopher2600/errors"
|
||||
"gopher2600/hardware/memory"
|
||||
"gopher2600/hardware/memory/bus"
|
||||
"gopher2600/television"
|
||||
)
|
||||
|
||||
|
@ -34,7 +34,7 @@ func (tia *TIA) Step(serviceMemory bool) (bool, error) {
|
|||
// update debugging information
|
||||
tia.videoCycles++
|
||||
|
||||
var memoryData memory.ChipData
|
||||
var memoryData bus.ChipData
|
||||
|
||||
// update memory if required
|
||||
if serviceMemory {
|
||||
|
|
|
@ -2,7 +2,7 @@ package tia
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"gopher2600/hardware/memory"
|
||||
"gopher2600/hardware/memory/bus"
|
||||
"gopher2600/hardware/tia/audio"
|
||||
"gopher2600/hardware/tia/future"
|
||||
"gopher2600/hardware/tia/phaseclock"
|
||||
|
@ -15,7 +15,7 @@ import (
|
|||
// TIA contains all the sub-components of the VCS TIA sub-system
|
||||
type TIA struct {
|
||||
tv television.Television
|
||||
mem memory.ChipBus
|
||||
mem bus.ChipBus
|
||||
|
||||
// number of video cycles since the last WSYNC. also cycles back to 0 on
|
||||
// RSYNC and when polycounter reaches count 56
|
||||
|
@ -92,7 +92,7 @@ func (tia TIA) String() string {
|
|||
}
|
||||
|
||||
// NewTIA creates a TIA, to be used in a VCS emulation
|
||||
func NewTIA(tv television.Television, mem memory.ChipBus) *TIA {
|
||||
func NewTIA(tv television.Television, mem bus.ChipBus) *TIA {
|
||||
tia := TIA{tv: tv, mem: mem, hblank: true}
|
||||
|
||||
var err error
|
||||
|
@ -124,7 +124,7 @@ func NewTIA(tv television.Television, mem memory.ChipBus) *TIA {
|
|||
// UpdateTIA checks for side effects in the TIA sub-system.
|
||||
//
|
||||
// Returns true if ChipData has *not* been serviced.
|
||||
func (tia *TIA) UpdateTIA(data memory.ChipData) bool {
|
||||
func (tia *TIA) UpdateTIA(data bus.ChipData) bool {
|
||||
switch data.Name {
|
||||
case "VSYNC":
|
||||
tia.sig.VSync = data.Value&0x02 == 0x02
|
||||
|
|
|
@ -2,12 +2,12 @@ package video
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"gopher2600/hardware/memory"
|
||||
"gopher2600/hardware/memory/addresses"
|
||||
"gopher2600/hardware/memory/bus"
|
||||
)
|
||||
|
||||
type collisions struct {
|
||||
mem memory.ChipBus
|
||||
mem bus.ChipBus
|
||||
|
||||
cxm0p uint8
|
||||
cxm1p uint8
|
||||
|
@ -19,7 +19,7 @@ type collisions struct {
|
|||
cxppmm uint8
|
||||
}
|
||||
|
||||
func newCollisions(mem memory.ChipBus) *collisions {
|
||||
func newCollisions(mem bus.ChipBus) *collisions {
|
||||
col := &collisions{mem: mem}
|
||||
col.clear()
|
||||
return col
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package video
|
||||
|
||||
import (
|
||||
"gopher2600/hardware/memory"
|
||||
"gopher2600/hardware/memory/addresses"
|
||||
"gopher2600/hardware/memory/bus"
|
||||
"gopher2600/hardware/tia/future"
|
||||
"gopher2600/hardware/tia/phaseclock"
|
||||
"gopher2600/hardware/tia/polycounter"
|
||||
|
@ -34,7 +34,7 @@ type Video struct {
|
|||
// pisel locatoin of the sprites in relation to the hsync counter (or
|
||||
// screen)
|
||||
func NewVideo(pclk *phaseclock.PhaseClock, hsync *polycounter.Polycounter,
|
||||
mem memory.ChipBus, tv television.Television,
|
||||
mem bus.ChipBus, tv television.Television,
|
||||
hblank, hmoveLatch *bool) *Video {
|
||||
|
||||
vd := &Video{
|
||||
|
@ -301,7 +301,7 @@ func (vd *Video) Pixel() (uint8, television.DebugColorSignal) {
|
|||
// CTRLPF is serviced in UpdateSpriteVariations()
|
||||
//
|
||||
// Returns true if ChipData has *not* been serviced.
|
||||
func (vd *Video) UpdatePlayfield(tiaDelay future.Scheduler, data memory.ChipData) bool {
|
||||
func (vd *Video) UpdatePlayfield(tiaDelay future.Scheduler, data bus.ChipData) bool {
|
||||
// homebrew Donkey Kong shows the need for a delay of at least two cycles
|
||||
// to write new playfield data
|
||||
switch data.Name {
|
||||
|
@ -322,7 +322,7 @@ func (vd *Video) UpdatePlayfield(tiaDelay future.Scheduler, data memory.ChipData
|
|||
// require a short pause, using the TIA scheduler
|
||||
//
|
||||
// Returns true if ChipData has *not* been serviced.
|
||||
func (vd *Video) UpdateSpriteHMOVE(tiaDelay future.Scheduler, data memory.ChipData) bool {
|
||||
func (vd *Video) UpdateSpriteHMOVE(tiaDelay future.Scheduler, data bus.ChipData) bool {
|
||||
switch data.Name {
|
||||
// horizontal movement values range from -8 to +7 for convenience we
|
||||
// convert this to the range 0 to 15. from TIA_HW_Notes.txt:
|
||||
|
@ -375,7 +375,7 @@ func (vd *Video) UpdateSpriteHMOVE(tiaDelay future.Scheduler, data memory.ChipDa
|
|||
// registers
|
||||
//
|
||||
// Returns true if memory.ChipData has not been serviced.
|
||||
func (vd *Video) UpdateSpritePositioning(data memory.ChipData) bool {
|
||||
func (vd *Video) UpdateSpritePositioning(data bus.ChipData) bool {
|
||||
switch data.Name {
|
||||
// the reset registers *must* be serviced after HSYNC has been ticked.
|
||||
// resets are resolved after a short delay, governed by the sprite itself
|
||||
|
@ -399,7 +399,7 @@ func (vd *Video) UpdateSpritePositioning(data memory.ChipData) bool {
|
|||
// UpdateColor checks the TIA memory for changes to color registers
|
||||
//
|
||||
// Returns true if memory.ChipData has not been serviced.
|
||||
func (vd *Video) UpdateColor(data memory.ChipData) bool {
|
||||
func (vd *Video) UpdateColor(data bus.ChipData) bool {
|
||||
switch data.Name {
|
||||
case "COLUP0":
|
||||
vd.Player0.setColor(data.Value & 0xfe)
|
||||
|
@ -423,7 +423,7 @@ func (vd *Video) UpdateColor(data memory.ChipData) bool {
|
|||
// occur after a call to Pixel()
|
||||
//
|
||||
// Returns true if memory.ChipData has not been serviced.
|
||||
func (vd *Video) UpdateSpritePixels(data memory.ChipData) bool {
|
||||
func (vd *Video) UpdateSpritePixels(data bus.ChipData) bool {
|
||||
// the barnstormer ROM demonstrate perfectly how GRP0 is affected if we
|
||||
// alter its state before a call to Pixel(). if we write do alter state
|
||||
// before Pixel(), then an unwanted artefact can be seen on scanline 61.
|
||||
|
@ -450,7 +450,7 @@ func (vd *Video) UpdateSpritePixels(data memory.ChipData) bool {
|
|||
// because it affects the ball sprite.
|
||||
//
|
||||
// Returns true if memory.ChipData has not been serviced.
|
||||
func (vd *Video) UpdateSpriteVariations(data memory.ChipData) bool {
|
||||
func (vd *Video) UpdateSpriteVariations(data bus.ChipData) bool {
|
||||
switch data.Name {
|
||||
case "CTRLPF":
|
||||
vd.Ball.setSize((data.Value & 0x30) >> 4)
|
||||
|
|
|
@ -31,7 +31,6 @@ const fieldSep = ", "
|
|||
const (
|
||||
lineMagicString int = iota
|
||||
lineCartName
|
||||
lineCartFormat
|
||||
lineCartHash
|
||||
lineTVtype
|
||||
numHeaderLines
|
||||
|
@ -45,7 +44,6 @@ func (rec *Recorder) writeHeader() error {
|
|||
// add header information
|
||||
lines[lineMagicString] = magicString
|
||||
lines[lineCartName] = rec.vcs.Mem.Cart.Filename
|
||||
lines[lineCartFormat] = rec.vcs.Mem.Cart.RequestedFormat
|
||||
lines[lineCartHash] = rec.vcs.Mem.Cart.Hash
|
||||
lines[lineTVtype] = fmt.Sprintf("%v\n", rec.vcs.TV.GetSpec().ID)
|
||||
|
||||
|
@ -73,7 +71,6 @@ func (plb *Playback) readHeader(lines []string) error {
|
|||
|
||||
// read header
|
||||
plb.CartLoad.Filename = lines[lineCartName]
|
||||
plb.CartLoad.Format = lines[lineCartFormat]
|
||||
plb.CartLoad.Hash = lines[lineCartHash]
|
||||
plb.TVtype = lines[lineTVtype]
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue