From 39fd8381dd371f063e2021fa7b467be9c5197998 Mon Sep 17 00:00:00 2001 From: JetSetIlly Date: Thu, 11 Jun 2020 13:14:29 +0100 Subject: [PATCH] remove Poke() from cartMapper interface. replaced with an argument to Write() all cartridge types are now poke-able all cartridge types are no patch-able reworked error types/messages. replaced some errors with panics --- debugger/commands.go | 13 ++- debugger/memory.go | 15 ++-- debugger/targets.go | 12 --- errors/messages.go | 11 ++- hardware/cpu/cpu.go | 32 ++++---- hardware/cpu/cpu_test.go | 4 +- hardware/cpu/execution/result.go | 6 +- hardware/memory/bus/debug_bus.go | 35 ++++---- hardware/memory/cartridge/cartridge.go | 10 +-- .../cartridge/harmony/mapper_dpcplus.go | 82 +++++++++++++------ hardware/memory/cartridge/mapper.go | 17 ++-- hardware/memory/cartridge/mapper_atari.go | 81 +++++++++--------- hardware/memory/cartridge/mapper_cbs.go | 59 +++++++------ hardware/memory/cartridge/mapper_dpc.go | 70 ++++++++++------ hardware/memory/cartridge/mapper_ejected.go | 25 ++---- hardware/memory/cartridge/mapper_mnetwork.go | 48 ++++++----- .../memory/cartridge/mapper_parkerbros.go | 55 ++++++++----- .../memory/cartridge/mapper_tigervision.go | 52 +++++++----- hardware/memory/chip.go | 9 +- hardware/memory/memory.go | 27 ++---- patch/doc.go | 10 +-- patch/patch.go | 12 +-- 22 files changed, 373 insertions(+), 312 deletions(-) diff --git a/debugger/commands.go b/debugger/commands.go index 14a38713..b90db92a 100644 --- a/debugger/commands.go +++ b/debugger/commands.go @@ -298,12 +298,14 @@ func (dbg *Debugger) processTokens(tokens *commandline.Tokens) (bool, error) { } } case "STATIC": + // !TODO: poke/peek static cartridge static data areas if db := dbg.VCS.Mem.Cart.GetDebugBus(); db != nil { dbg.printInstrument(db.GetStatic()) } else { dbg.printLine(terminal.StyleFeedback, "cartridge has no static data areas") } case "REGISTERS": + // !TODO: poke/peek cartridge registers bus := dbg.VCS.Mem.Cart.GetDebugBus() if bus != nil { dbg.printInstrument(bus.GetRegisters()) @@ -312,6 +314,8 @@ func (dbg *Debugger) processTokens(tokens *commandline.Tokens) (bool, error) { } case "RAM": + // cartridge RAM is accessible through the normal VCS buses so + // the normal peek/poke commands will work bus := dbg.VCS.Mem.Cart.GetRAMbus() if bus != nil { s := &strings.Builder{} @@ -725,10 +729,14 @@ func (dbg *Debugger) processTokens(tokens *commandline.Tokens) (bool, error) { // get address token a, _ := tokens.Get() - // convert address + // convert address. note that the calls to dbgmem.poke() also call + // mapAddress(). the reason we map the address here is because we want + // a numeric address that we can iterate with in the for loop below. + // simply converting to a number is no good because we want the user to + // be able to specify an address by name, so we may as well just call + // mapAddress, even if it does seem redundant. ai := dbg.dbgmem.mapAddress(a, false) if ai == nil { - // using poke error because hexload is basically the same as poking dbg.printLine(terminal.StyleError, errors.New(errors.UnpokeableAddress, a).Error()) return false, nil } @@ -745,7 +753,6 @@ func (dbg *Debugger) processTokens(tokens *commandline.Tokens) (bool, error) { continue // for loop (without advancing address) } - // perform individual poke ai, err := dbg.dbgmem.poke(addr, uint8(val)) if err != nil { dbg.printLine(terminal.StyleError, "%s", err) diff --git a/debugger/memory.go b/debugger/memory.go index a41ee8cd..66c59bc7 100644 --- a/debugger/memory.go +++ b/debugger/memory.go @@ -148,12 +148,10 @@ func (dbgmem memoryDebug) peek(address interface{}) (*addressInfo, error) { return nil, errors.New(errors.DebuggerError, errors.New(errors.UnpeekableAddress, address)) } - ar, err := dbgmem.mem.GetArea(ai.area) - if err != nil { - return nil, errors.New(errors.DebuggerError, err) - } + area := dbgmem.mem.GetArea(ai.area) - ai.data, err = ar.Peek(ai.mappedAddress) + var err error + ai.data, err = area.Peek(ai.mappedAddress) if err != nil { return nil, errors.New(errors.DebuggerError, err) } @@ -171,12 +169,9 @@ func (dbgmem memoryDebug) poke(address interface{}, data uint8) (*addressInfo, e return nil, errors.New(errors.DebuggerError, errors.New(errors.UnpokeableAddress, address)) } - ar, err := dbgmem.mem.GetArea(ai.area) - if err != nil { - return nil, errors.New(errors.DebuggerError, err) - } + area := dbgmem.mem.GetArea(ai.area) - err = ar.Poke(ai.mappedAddress, data) + err := area.Poke(ai.mappedAddress, data) if err != nil { return nil, errors.New(errors.DebuggerError, err) } diff --git a/debugger/targets.go b/debugger/targets.go index 40c08823..7e03210c 100644 --- a/debugger/targets.go +++ b/debugger/targets.go @@ -215,18 +215,6 @@ func parseTarget(dbg *Debugger, tokens *commandline.Tokens) (*target, error) { }, } - case "BUS": - trg = &target{ - label: "Bus Error", - currentValue: func() interface{} { - s := dbg.VCS.CPU.LastResult.BusError - if s == "" { - return "ok" - } - return s - }, - } - default: return nil, errors.New(errors.InvalidTarget, fmt.Sprintf("%s %s", keyword, subkey)) } diff --git a/errors/messages.go b/errors/messages.go index 52e3250f..487d5d1a 100644 --- a/errors/messages.go +++ b/errors/messages.go @@ -105,16 +105,15 @@ const ( CPUBug = "cpu bug: %v" // memory - MemoryError = "memory error: %v" UnpokeableAddress = "memory error: cannot poke address (%v)" UnpeekableAddress = "memory error: cannot peek address (%v)" - BusError = "bus error: address %#04x" + MemoryBusError = "memory error: inaccessible address (%v)" // cartridges - CartridgeError = "cartridge error: %v" - CartridgeEjected = "cartridge error: no cartridge attached" - UnpatchableCartType = "cartridge error: cannot patch this cartridge type (%v)" - CartridgeStaticOOB = "cartridge error: static data address to high (%#04x)" + CartridgeError = "cartridge error: %v" + CartridgeEjected = "cartridge error: no cartridge attached" + CartridgePatchOOB = "cartrdige error: patch offset too high (%#04x)" + CartridgeStaticOOB = "cartridge error: static data address too high (%#04x)" // input UnknownInputEvent = "input error: %v: unsupported event (%v)" diff --git a/hardware/cpu/cpu.go b/hardware/cpu/cpu.go index 96f04d13..338eeeaf 100644 --- a/hardware/cpu/cpu.go +++ b/hardware/cpu/cpu.go @@ -189,10 +189,10 @@ func (mc *CPU) read8Bit(address uint16) (uint8, error) { val, err := mc.mem.Read(address) if err != nil { - if !errors.Is(err, errors.BusError) { + if !errors.Is(err, errors.MemoryBusError) { return 0, err } - mc.LastResult.BusError = err.Error() + mc.LastResult.Error = err.Error() } // +1 cycle @@ -211,10 +211,10 @@ func (mc *CPU) read8BitZeroPage(address uint8) (uint8, error) { val, err := mc.mem.ReadZeroPage(address) if err != nil { - if !errors.Is(err, errors.BusError) { + if !errors.Is(err, errors.MemoryBusError) { return 0, err } - mc.LastResult.BusError = err.Error() + mc.LastResult.Error = err.Error() } // +1 cycle @@ -237,10 +237,10 @@ func (mc *CPU) write8Bit(address uint16, value uint8) error { if err != nil { // don't worry about unwritable addresses (unless strict addressing // is on) - if !errors.Is(err, errors.BusError) { + if !errors.Is(err, errors.MemoryBusError) { return err } - mc.LastResult.BusError = err.Error() + mc.LastResult.Error = err.Error() } return nil @@ -252,10 +252,10 @@ func (mc *CPU) write8Bit(address uint16, value uint8) error { func (mc *CPU) read16Bit(address uint16) (uint16, error) { lo, err := mc.mem.Read(address) if err != nil { - if !errors.Is(err, errors.BusError) { + if !errors.Is(err, errors.MemoryBusError) { return 0, err } - mc.LastResult.BusError = err.Error() + mc.LastResult.Error = err.Error() } // +1 cycle @@ -266,10 +266,10 @@ func (mc *CPU) read16Bit(address uint16) (uint16, error) { hi, err := mc.mem.Read(address + 1) if err != nil { - if !errors.Is(err, errors.BusError) { + if !errors.Is(err, errors.MemoryBusError) { return 0, err } - mc.LastResult.BusError = err.Error() + mc.LastResult.Error = err.Error() } // +1 cycle @@ -291,10 +291,10 @@ func (mc *CPU) read8BitPC(val *uint8, f func() error) error { v, err := mc.mem.Read(mc.PC.Address()) if err != nil { - if !errors.Is(err, errors.BusError) { + if !errors.Is(err, errors.MemoryBusError) { return err } - mc.LastResult.BusError = err.Error() + mc.LastResult.Error = err.Error() } carry, _ := mc.PC.Add(1) @@ -601,19 +601,19 @@ func (mc *CPU) ExecuteInstruction(cycleCallback func() error) error { lo, err := mc.mem.Read(indirectAddress) if err != nil { - if !errors.Is(err, errors.BusError) { + if !errors.Is(err, errors.MemoryBusError) { return err } - mc.LastResult.BusError = err.Error() + mc.LastResult.Error = err.Error() } // +1 cycle err = mc.endCycle() if err != nil { - if !errors.Is(err, errors.BusError) { + if !errors.Is(err, errors.MemoryBusError) { return err } - mc.LastResult.BusError = err.Error() + mc.LastResult.Error = err.Error() return err } diff --git a/hardware/cpu/cpu_test.go b/hardware/cpu/cpu_test.go index 15673fcd..e47b2733 100644 --- a/hardware/cpu/cpu_test.go +++ b/hardware/cpu/cpu_test.go @@ -66,7 +66,7 @@ func (mem *mockMem) Clear() { func (mem mockMem) Read(address uint16) (uint8, error) { if address&0xff00 == 0xff00 { - return 0, errors.New(errors.BusError, address) + return 0, errors.New(errors.MemoryBusError, address) } return mem.internal[address], nil } @@ -77,7 +77,7 @@ func (mem mockMem) ReadZeroPage(address uint8) (uint8, error) { func (mem *mockMem) Write(address uint16, data uint8) error { if address&0xff00 == 0xff00 { - return errors.New(errors.BusError, address) + return errors.New(errors.MemoryBusError, address) } mem.internal[address] = data return nil diff --git a/hardware/cpu/execution/result.go b/hardware/cpu/execution/result.go index 5a831030..5859cf86 100644 --- a/hardware/cpu/execution/result.go +++ b/hardware/cpu/execution/result.go @@ -66,8 +66,8 @@ type Result struct { // whether a known buggy code path (in the emulated CPU) was triggered CPUBug string - // whether the last memory access resulted in a bus error - BusError string + // error string. will be a memory access error + Error string // whether this data has been finalised - some fields in this struct will // be undefined if Final is false @@ -83,6 +83,6 @@ func (r *Result) Reset() { r.ActualCycles = 0 r.PageFault = false r.CPUBug = "" - r.BusError = "" + r.Error = "" r.Final = false } diff --git a/hardware/memory/bus/debug_bus.go b/hardware/memory/bus/debug_bus.go index ce8495ce..d5cf5e9d 100644 --- a/hardware/memory/bus/debug_bus.go +++ b/hardware/memory/bus/debug_bus.go @@ -33,27 +33,28 @@ type DebuggerBus interface { Poke(address uint16, value uint8) error } -// CartDebugBus defines the operations required for a debugger to access -// non-addressable areas of a cartridge. You have to know the precise cartridge -// mapper for PutRegister() to work effectively. +// CartDebugBus defines the operations required for a debugger to access the +// static and special function areas of a cartrudge. // // The mapper is allowed to panic if it is not interfaced with correctly. // -// So what's the point of the interface if you need to know the details of the -// underlying type? Well, it goes some way to helping us understand what parts -// of the cartridge are beyond the scope of the regular buses. +// You should know the precise cartridge mapper for the CartRegister and +// CartStatic type to be usable. // -// Primarily though, it is useful when used in conjunction with the lazy -// evaluation system used by GUI systems running in a different goroutine. The -// point of the lazy system is to prevent race conditions, the way we do that -// is to make a copy of the system variable 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? Well we could, but it would mean another -// place where the cartridge 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. +// 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 CartDebugBus interface { // GetRegisters returns a copy of the cartridge's registers GetRegisters() CartRegisters diff --git a/hardware/memory/cartridge/cartridge.go b/hardware/memory/cartridge/cartridge.go index 3724c407..5d66551e 100644 --- a/hardware/memory/cartridge/cartridge.go +++ b/hardware/memory/cartridge/cartridge.go @@ -65,16 +65,14 @@ func (cart *Cartridge) Peek(addr uint16) (uint8, error) { return cart.Read(addr) } -// Poke is an implementation of memory.DebuggerBus. This poke pokes the current -// cartridge bank. See Patch for a different method. Address must be -// normalised. +// Poke is an implementation of memory.DebuggerBus. Address must be normalised. func (cart *Cartridge) Poke(addr uint16, data uint8) error { - return cart.mapper.Poke(addr^memorymap.OriginCart, data) + return cart.mapper.Write(addr^memorymap.OriginCart, data, true) } // Patch writes to cartridge memory. Offset is measured from the start of // cartridge memory. It differs from Poke in that respect -func (cart *Cartridge) Patch(offset uint16, data uint8) error { +func (cart *Cartridge) Patch(offset int, data uint8) error { return cart.mapper.Patch(offset, data) } @@ -85,7 +83,7 @@ func (cart *Cartridge) Read(addr uint16) (uint8, error) { // Write is an implementation of memory.CPUBus. Address must be normalised. func (cart *Cartridge) Write(addr uint16, data uint8) error { - return cart.mapper.Write(addr^memorymap.OriginCart, data) + return cart.mapper.Write(addr^memorymap.OriginCart, data, false) } // Eject removes memory from cartridge space and unlike the real hardware, diff --git a/hardware/memory/cartridge/harmony/mapper_dpcplus.go b/hardware/memory/cartridge/harmony/mapper_dpcplus.go index 99ec721e..c96d5914 100644 --- a/hardware/memory/cartridge/harmony/mapper_dpcplus.go +++ b/hardware/memory/cartridge/harmony/mapper_dpcplus.go @@ -32,8 +32,9 @@ type dpcPlus struct { description string // banks and the currently selected bank - banks [][]byte - bank int + bankSize int + banks [][]byte + bank int registers DPCplusRegisters static DPCplusStatic @@ -44,24 +45,36 @@ type dpcPlus struct { // music fetchers are clocked at a fixed (slower) rate than the reference // to the VCS's clock. see Step() function. beats int + + // patch help. offsets in the original data file for the different areas + // in the cartridge + // + // we only do this because of the complexity of the dpcPlus file and only + // for the purposes of the Patch() function. we don't bother with anything + // like this for the simpler cartridge formats + banksOffset int + dataOffset int + freqOffset int + fileSize int } // NewDPCplus is the preferred method of initialisation for the harmony type func NewDPCplus(data []byte) (*dpcPlus, error) { const armSize = 3072 - const bankSize = 4096 const dataSize = 4096 const freqSize = 1024 - cart := &dpcPlus{} - cart.mappingID = "DPC+" - cart.description = "DPC+ (Harmony)" + cart := &dpcPlus{ + mappingID: "DPC+", + description: "DPC+ (Harmony)", + bankSize: 4096, + } // amount of data used for cartridges bankLen := len(data) - dataSize - armSize - freqSize // size check - if bankLen%bankSize != 0 { + if bankLen%cart.bankSize != 0 { return nil, errors.New(errors.CartridgeError, fmt.Sprintf("%s: %d bytes not supported", cart.mappingID, len(data))) } @@ -69,24 +82,30 @@ func NewDPCplus(data []byte) (*dpcPlus, error) { cart.static.Arm = data[:armSize] // allocate enough banks - cart.banks = make([][]uint8, bankLen/bankSize) + cart.banks = make([][]uint8, bankLen/cart.bankSize) // partition data into banks for k := 0; k < cart.NumBanks(); k++ { - cart.banks[k] = make([]uint8, bankSize) - offset := k * bankSize + cart.banks[k] = make([]uint8, cart.bankSize) + offset := k * cart.bankSize offset += armSize - cart.banks[k] = data[offset : offset+bankSize] + cart.banks[k] = data[offset : offset+cart.bankSize] } // gfx and frequency table at end of file - s := armSize + (bankSize * cart.NumBanks()) - cart.static.Data = data[s : s+dataSize] - cart.static.Freq = data[s+dataSize:] + dataOffset := armSize + (cart.bankSize * cart.NumBanks()) + cart.static.Data = data[dataOffset : dataOffset+dataSize] + cart.static.Freq = data[dataOffset+dataSize:] // initialise cartridge before returning success cart.Initialise() + // patch offsets + cart.banksOffset = armSize + cart.dataOffset = dataOffset + cart.freqOffset = dataOffset + dataSize + cart.fileSize = len(data) + return cart, nil } @@ -141,7 +160,7 @@ func (cart *dpcPlus) Read(addr uint16) (uint8, error) { } if addr > 0x0027 { - return 0, errors.New(errors.BusError, addr) + return 0, errors.New(errors.MemoryBusError, addr) } switch addr { @@ -260,7 +279,7 @@ func (cart *dpcPlus) Read(addr uint16) (uint8, error) { return data, nil } -func (cart *dpcPlus) Write(addr uint16, data uint8) error { +func (cart *dpcPlus) Write(addr uint16, data uint8, poke bool) error { // if address is above register space then we only need to check for bank // switching before returning data at the quoted address if addr == 0x0ff6 { @@ -278,7 +297,7 @@ func (cart *dpcPlus) Write(addr uint16, data uint8) error { } if addr < 0x0028 || addr > 0x007f { - return errors.New(errors.BusError, addr) + return errors.New(errors.MemoryBusError, addr) } switch addr { @@ -548,7 +567,12 @@ func (cart *dpcPlus) Write(addr uint16, data uint8) error { cart.registers.Fetcher[f].inc() } - return nil + if poke { + cart.banks[cart.bank][addr] = data + return nil + } + + return errors.New(errors.MemoryBusError, addr) } func (cart dpcPlus) NumBanks() int { @@ -572,12 +596,24 @@ func (cart *dpcPlus) RestoreState(state interface{}) error { return nil } -func (cart *dpcPlus) Poke(addr uint16, data uint8) error { - return errors.New(errors.UnpokeableAddress, addr) -} +func (cart *dpcPlus) Patch(offset int, data uint8) error { + if offset >= cart.fileSize { + return errors.New(errors.CartridgePatchOOB, offset) + } -func (cart *dpcPlus) Patch(addr uint16, data uint8) error { - return errors.New(errors.UnpatchableCartType, cart.description) + if offset >= cart.freqOffset { + cart.static.Freq[offset-cart.freqOffset] = data + } else if offset >= cart.dataOffset { + cart.static.Data[offset-cart.dataOffset] = data + } else if offset >= cart.banksOffset { + bank := int(offset) / cart.bankSize + offset = offset % cart.bankSize + cart.banks[bank][offset] = data + } else { + cart.static.Arm[offset-cart.banksOffset] = data + } + + return nil } func (cart *dpcPlus) Listen(addr uint16, data uint8) { diff --git a/hardware/memory/cartridge/mapper.go b/hardware/memory/cartridge/mapper.go index 2d50a53c..47114dcb 100644 --- a/hardware/memory/cartridge/mapper.go +++ b/hardware/memory/cartridge/mapper.go @@ -27,23 +27,18 @@ type cartMapper interface { Initialise() ID() string Read(addr uint16) (data uint8, err error) - Write(addr uint16, data uint8) error + Write(addr uint16, data uint8, poke bool) error NumBanks() int GetBank(addr uint16) (bank int) SetBank(addr uint16, bank int) error SaveState() interface{} RestoreState(interface{}) error - // poke new value anywhere into currently selected bank of cartridge memory - // (including ROM). - Poke(addr uint16, data uint8) error - - // cartMapper does not need a dedicated Peek() function. the Cartridge type - // implements Peek() and can just call the cartMapper's Read() function - - // patch differs from poke in that it alters the data as though it was - // being read from disk - Patch(offset uint16, data uint8) error + // 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 // see the commentary for the Listen() function in the Cartridge type for // an explanation for what this does diff --git a/hardware/memory/cartridge/mapper_atari.go b/hardware/memory/cartridge/mapper_atari.go index 1cd7ee80..2fb98ff2 100644 --- a/hardware/memory/cartridge/mapper_atari.go +++ b/hardware/memory/cartridge/mapper_atari.go @@ -72,11 +72,10 @@ type atari struct { mappingID string description string - bankSize int - // atari formats apart from 2k and 4k are divided into banks. 2k and 4k // ROMs conceptually have one bank - banks [][]uint8 + bankSize int + banks [][]uint8 // identifies the currently selected bank bank int @@ -155,13 +154,19 @@ func (cart *atari) Read(addr uint16) (uint8, bool) { } // Write implements the cartMapper interface -func (cart *atari) Write(addr uint16, data uint8) bool { +func (cart *atari) Write(addr uint16, data uint8, poke bool) bool { if cart.ram != nil { if addr <= 127 { cart.ram[addr] = data return true } } + + if poke { + cart.banks[cart.bank][addr] = data + return true + } + return false } @@ -194,22 +199,20 @@ func (cart *atari) addSuperchip() bool { return true } -// Poke implements the cartMapper interface -func (cart *atari) Poke(addr uint16, data uint8) error { - cart.banks[cart.bank][addr] = data - return nil -} - // Patch implements the cartMapper interface -func (cart *atari) Patch(addr uint16, data uint8) error { - bank := int(addr) / cart.bankSize - addr = addr % uint16(cart.bankSize) - cart.banks[bank][addr] = data +func (cart *atari) Patch(offset int, data uint8) error { + if offset >= cart.bankSize*len(cart.banks) { + return errors.New(errors.CartridgePatchOOB, offset) + } + + bank := int(offset) / cart.bankSize + offset = offset % cart.bankSize + cart.banks[bank][offset] = data return nil } // Listen implements the cartMapper interface -func (cart *atari) Listen(addr uint16, data uint8) { +func (cart *atari) Listen(_ uint16, _ uint8) { } // Step implements the cartMapper interface @@ -284,12 +287,12 @@ func (cart *atari4k) Read(addr uint16) (uint8, error) { } // Write implements the cartMapper interface -func (cart *atari4k) Write(addr uint16, data uint8) error { - if ok := cart.atari.Write(addr, data); ok { +func (cart *atari4k) Write(addr uint16, data uint8, poke bool) error { + if ok := cart.atari.Write(addr, data, poke); ok { return nil } - return errors.New(errors.BusError, addr) + return errors.New(errors.MemoryBusError, addr) } // atari2k is the half-size cartridge of 2048 bytes @@ -335,12 +338,12 @@ func (cart *atari2k) Read(addr uint16) (uint8, error) { } // Write implements the cartMapper interface -func (cart *atari2k) Write(addr uint16, data uint8) error { - if ok := cart.atari.Write(addr, data); ok { +func (cart *atari2k) Write(addr uint16, data uint8, poke bool) error { + if ok := cart.atari.Write(addr, data, poke); ok { return nil } - return errors.New(errors.BusError, addr) + return errors.New(errors.MemoryBusError, addr) } // atari8k (F8) @@ -396,17 +399,15 @@ func (cart *atari8k) Read(addr uint16) (uint8, error) { } // Write implements the cartMapper interface -func (cart *atari8k) Write(addr uint16, data uint8) error { - if ok := cart.atari.Write(addr, data); ok { - return nil - } - +func (cart *atari8k) Write(addr uint16, data uint8, poke bool) error { if addr == 0x0ff8 { cart.bank = 0 } else if addr == 0x0ff9 { cart.bank = 1 - } else { - return errors.New(errors.BusError, addr) + } + + if ok := cart.atari.Write(addr, data, poke); !ok { + return errors.New(errors.MemoryBusError, addr) } return nil @@ -470,11 +471,7 @@ func (cart *atari16k) Read(addr uint16) (uint8, error) { } // Write implements the cartMapper interface -func (cart *atari16k) Write(addr uint16, data uint8) error { - if ok := cart.atari.Write(addr, data); ok { - return nil - } - +func (cart *atari16k) Write(addr uint16, data uint8, poke bool) error { if addr == 0x0ff6 { cart.bank = 0 } else if addr == 0x0ff7 { @@ -483,8 +480,10 @@ func (cart *atari16k) Write(addr uint16, data uint8) error { cart.bank = 2 } else if addr == 0x0ff9 { cart.bank = 3 - } else { - return errors.New(errors.BusError, addr) + } + + if ok := cart.atari.Write(addr, data, poke); !ok { + return errors.New(errors.MemoryBusError, addr) } return nil @@ -556,11 +555,7 @@ func (cart *atari32k) Read(addr uint16) (uint8, error) { } // Write implements the cartMapper interface -func (cart *atari32k) Write(addr uint16, data uint8) error { - if ok := cart.atari.Write(addr, data); ok { - return nil - } - +func (cart *atari32k) Write(addr uint16, data uint8, poke bool) error { if addr == 0x0ff4 { cart.bank = 0 } else if addr == 0x0ff5 { @@ -577,8 +572,10 @@ func (cart *atari32k) Write(addr uint16, data uint8) error { cart.bank = 6 } else if addr == 0x0ffb { cart.bank = 7 - } else { - return errors.New(errors.BusError, addr) + } + + if ok := cart.atari.Write(addr, data, poke); !ok { + return errors.New(errors.MemoryBusError, addr) } return nil diff --git a/hardware/memory/cartridge/mapper_cbs.go b/hardware/memory/cartridge/mapper_cbs.go index 1699f69c..85892b40 100644 --- a/hardware/memory/cartridge/mapper_cbs.go +++ b/hardware/memory/cartridge/mapper_cbs.go @@ -31,7 +31,8 @@ type cbs struct { description string // cbs cartridges have 3 banks of 4096 bytes - banks [][]uint8 + bankSize int + banks [][]uint8 // identifies the currently selected bank bank int @@ -41,25 +42,24 @@ type cbs struct { } func newCBS(data []byte) (cartMapper, error) { - const bankSize = 4096 + cart := &cbs{ + description: "CBS", + mappingID: "FA", + bankSize: 4096, + ram: make([]uint8, 256), + } - cart := &cbs{} - cart.description = "CBS" - cart.mappingID = "FA" - cart.banks = make([][]uint8, cart.NumBanks()) - - if len(data) != bankSize*cart.NumBanks() { + if len(data) != cart.bankSize*cart.NumBanks() { return nil, errors.New(errors.CartridgeError, fmt.Sprintf("%s: wrong number of bytes in the cartridge file", cart.mappingID)) } - for k := 0; k < cart.NumBanks(); k++ { - cart.banks[k] = make([]uint8, bankSize) - offset := k * bankSize - copy(cart.banks[k], data[offset:offset+bankSize]) - } + cart.banks = make([][]uint8, cart.NumBanks()) - // 256 bytes of cartidge ram in all instances - cart.ram = make([]uint8, 256) + for k := 0; k < cart.NumBanks(); k++ { + cart.banks[k] = make([]uint8, cart.bankSize) + offset := k * cart.bankSize + copy(cart.banks[k], data[offset:offset+cart.bankSize]) + } cart.Initialise() @@ -103,7 +103,7 @@ func (cart *cbs) Read(addr uint16) (uint8, error) { } // Write implements the cartMapper interface -func (cart *cbs) Write(addr uint16, data uint8) error { +func (cart *cbs) Write(addr uint16, data uint8, poke bool) error { if addr <= 0x00ff { cart.ram[addr] = data return nil @@ -115,11 +115,14 @@ func (cart *cbs) Write(addr uint16, data uint8) error { cart.bank = 1 } else if addr == 0x0ffa { cart.bank = 2 - } else { - return errors.New(errors.BusError, addr) } - return nil + if poke { + cart.banks[cart.bank][addr] = data + return nil + } + + return errors.New(errors.MemoryBusError, addr) } // NumBanks implements the cartMapper interface @@ -154,18 +157,20 @@ func (cart *cbs) RestoreState(state interface{}) error { return nil } -// Poke implements the cartMapper interface -func (cart *cbs) Poke(addr uint16, data uint8) error { - return errors.New(errors.UnpokeableAddress, addr) -} - // Patch implements the cartMapper interface -func (cart *cbs) Patch(addr uint16, data uint8) error { - return errors.New(errors.UnpatchableCartType, cart.mappingID) +func (cart *cbs) Patch(offset int, data uint8) error { + if offset >= cart.bankSize*len(cart.banks) { + return errors.New(errors.CartridgePatchOOB, offset) + } + + bank := int(offset) / cart.bankSize + offset = offset % cart.bankSize + cart.banks[bank][offset] = data + return nil } // Listen implements the cartMapper interface -func (cart *cbs) Listen(addr uint16, data uint8) { +func (cart *cbs) Listen(_ uint16, _ uint8) { } // Step implements the cartMapper interface diff --git a/hardware/memory/cartridge/mapper_dpc.go b/hardware/memory/cartridge/mapper_dpc.go index dea8323c..94923462 100644 --- a/hardware/memory/cartridge/mapper_dpc.go +++ b/hardware/memory/cartridge/mapper_dpc.go @@ -33,12 +33,19 @@ type dpc struct { description string // banks and the currently selected bank - banks [][]byte - bank int + bankSize int + banks [][]byte + bank int - static DPCstatic + // DPC registers are directly accessible by the VCS but have a special + // meaning when written to and read. the DPCregisters type implements the + // functionality of these special addresses and a copy of the field is + // returned by the GetRegisters() function registers DPCregisters + // dpc specific areas of the cartridge, not accessible by the normal VCS bus + static DPCstatic + // the OSC clock found in DPC cartridges runs at slower than the VCS itself // to effectively emulate the slower clock therefore, we need to discount // the excess steps. see the step() function for details @@ -126,7 +133,6 @@ func (df *DPCdataFetcher) clk() { func (df *DPCdataFetcher) setFlag() { // set flag register [col 6, ln 7-12] - if df.Low == df.Top { df.Flag = true } else if df.Low == df.Bottom { @@ -135,26 +141,28 @@ func (df *DPCdataFetcher) setFlag() { } func newDPC(data []byte) (cartMapper, error) { - const bankSize = 4096 - const gfxSize = 2048 + const staticSize = 2048 + + cart := &dpc{ + mappingID: "DPC", + description: "DPC Pitfall2 style", + bankSize: 4096, + } - cart := &dpc{} - cart.mappingID = "DPC" - cart.description = "DPC Pitfall2 style" cart.banks = make([][]uint8, cart.NumBanks()) - if len(data) < bankSize*cart.NumBanks()+gfxSize { + if len(data) < cart.bankSize*cart.NumBanks()+staticSize { return nil, errors.New(errors.CartridgeError, fmt.Sprintf("%s: wrong number of bytes in the cartridge file", cart.mappingID)) } for k := 0; k < cart.NumBanks(); k++ { - cart.banks[k] = make([]uint8, bankSize) - offset := k * bankSize - cart.banks[k] = data[offset : offset+bankSize] + cart.banks[k] = make([]uint8, cart.bankSize) + offset := k * cart.bankSize + cart.banks[k] = data[offset : offset+cart.bankSize] } - gfxStart := cart.NumBanks() * bankSize - cart.static.Gfx = data[gfxStart : gfxStart+gfxSize] + staticStart := cart.NumBanks() * cart.bankSize + cart.static.Gfx = data[staticStart : staticStart+staticSize] cart.Initialise() @@ -293,7 +301,7 @@ func (cart *dpc) Read(addr uint16) (uint8, error) { } // Write implements the cartMapper interface -func (cart *dpc) Write(addr uint16, data uint8) error { +func (cart *dpc) Write(addr uint16, data uint8, poke bool) error { if addr == 0x0ff8 { cart.bank = 0 } else if addr == 0x0ff9 { @@ -348,7 +356,12 @@ func (cart *dpc) Write(addr uint16, data uint8) error { // other addresses are not write registers and are ignored } - return nil + if poke { + cart.banks[cart.bank][addr] = data + return nil + } + + return errors.New(errors.MemoryBusError, addr) } // NumBanks implements the cartMapper interface @@ -377,18 +390,25 @@ func (cart *dpc) RestoreState(state interface{}) error { return nil } -// Poke implements the cartMapper interface -func (cart *dpc) Poke(addr uint16, data uint8) error { - return errors.New(errors.UnpokeableAddress, addr) -} - // Patch implements the cartMapper interface -func (cart *dpc) Patch(addr uint16, data uint8) error { - return errors.New(errors.UnpatchableCartType, cart.description) +func (cart *dpc) Patch(offset int, data uint8) error { + if offset >= cart.bankSize*len(cart.banks)+len(cart.static.Gfx) { + return errors.New(errors.CartridgePatchOOB, offset) + } + + staticStart := cart.NumBanks() * cart.bankSize + if staticStart >= staticStart { + cart.static.Gfx[offset] = data + } else { + bank := int(offset) / cart.bankSize + offset = offset % cart.bankSize + cart.banks[bank][offset] = data + } + return nil } // Listen implements the cartMapper interface -func (cart *dpc) Listen(addr uint16, data uint8) { +func (cart *dpc) Listen(_ uint16, _ uint8) { } // Step implements the cartMapper interface diff --git a/hardware/memory/cartridge/mapper_ejected.go b/hardware/memory/cartridge/mapper_ejected.go index 846e89d4..46b0ab65 100644 --- a/hardware/memory/cartridge/mapper_ejected.go +++ b/hardware/memory/cartridge/mapper_ejected.go @@ -20,8 +20,6 @@ package cartridge import ( - "fmt" - "github.com/jetsetilly/gopher2600/errors" ) @@ -56,12 +54,12 @@ func (cart *ejected) Initialise() { } // Read implements the cartMapper interface -func (cart *ejected) Read(addr uint16) (uint8, error) { +func (cart *ejected) Read(_ uint16) (uint8, error) { return 0, errors.New(errors.CartridgeEjected) } // Write implements the cartMapper interface -func (cart *ejected) Write(addr uint16, data uint8) error { +func (cart *ejected) Write(_ uint16, _ uint8, _ bool) error { return errors.New(errors.CartridgeEjected) } @@ -71,12 +69,12 @@ func (cart ejected) NumBanks() int { } // SetBank implements the cartMapper interface -func (cart *ejected) SetBank(addr uint16, bank int) error { - return errors.New(errors.CartridgeError, fmt.Sprintf("ejected cartridge")) +func (cart *ejected) SetBank(_ uint16, _ int) error { + return errors.New(errors.CartridgeEjected) } // GetBank implements the cartMapper interface -func (cart ejected) GetBank(addr uint16) int { +func (cart ejected) GetBank(_ uint16) int { return 0 } @@ -86,22 +84,17 @@ func (cart *ejected) SaveState() interface{} { } // RestoreState implements the cartMapper interface -func (cart *ejected) RestoreState(state interface{}) error { +func (cart *ejected) RestoreState(_ interface{}) error { return nil } -// Poke implements the cartMapper interface -func (cart *ejected) Poke(addr uint16, data uint8) error { - return errors.New(errors.UnpokeableAddress, addr) -} - // Patch implements the cartMapper interface -func (cart *ejected) Patch(addr uint16, data uint8) error { - return errors.New(errors.UnpatchableCartType, cart.description) +func (cart *ejected) Patch(_ int, _ uint8) error { + return errors.New(errors.CartridgeEjected) } // Listen implements the cartMapper interface -func (cart *ejected) Listen(addr uint16, data uint8) { +func (cart *ejected) Listen(_ uint16, _ uint8) { } // Step implements the cartMapper interface diff --git a/hardware/memory/cartridge/mapper_mnetwork.go b/hardware/memory/cartridge/mapper_mnetwork.go index 5d05f60c..acfaf1f1 100644 --- a/hardware/memory/cartridge/mapper_mnetwork.go +++ b/hardware/memory/cartridge/mapper_mnetwork.go @@ -86,6 +86,8 @@ type mnetwork struct { mappingID string description string + bankSize int + banks [][]uint8 bank int @@ -104,21 +106,22 @@ type mnetwork struct { } func newMnetwork(data []byte) (cartMapper, error) { - const bankSize = 2048 + cart := &mnetwork{ + description: "m-network", + mappingID: "E7", + bankSize: 2048, + } - cart := &mnetwork{} - cart.description = "m-network" - cart.mappingID = "E7" cart.banks = make([][]uint8, cart.NumBanks()) - if len(data) != bankSize*cart.NumBanks() { + if len(data) != cart.bankSize*cart.NumBanks() { return nil, errors.New(errors.CartridgeError, fmt.Sprintf("%s: wrong number of bytes in the cartridge file", cart.mappingID)) } for k := 0; k < cart.NumBanks(); k++ { - cart.banks[k] = make([]uint8, bankSize) - offset := k * bankSize - copy(cart.banks[k], data[offset:offset+bankSize]) + cart.banks[k] = make([]uint8, cart.bankSize) + offset := k * cart.bankSize + copy(cart.banks[k], data[offset:offset+cart.bankSize]) } // not all m-network cartridges have any RAM but we'll allocate it for all @@ -186,14 +189,14 @@ func (cart *mnetwork) Read(addr uint16) (uint8, error) { cart.bankSwitchOnAccess(addr) } } else { - return 0, errors.New(errors.BusError, addr) + return 0, errors.New(errors.MemoryBusError, addr) } return data, nil } // Write implements the cartMapper interface -func (cart *mnetwork) Write(addr uint16, data uint8) error { +func (cart *mnetwork) Write(addr uint16, data uint8, poke bool) error { if addr >= 0x0000 && addr <= 0x07ff { if addr <= 0x03ff && cart.bank == 7 { cart.ram1k[addr&0x03ff] = data @@ -206,7 +209,12 @@ func (cart *mnetwork) Write(addr uint16, data uint8) error { return nil } - return errors.New(errors.BusError, addr) + if poke { + cart.banks[cart.bank][addr] = data + return nil + } + + return errors.New(errors.MemoryBusError, addr) } func (cart *mnetwork) bankSwitchOnAccess(addr uint16) bool { @@ -311,18 +319,20 @@ func (cart *mnetwork) RestoreState(state interface{}) error { return nil } -// Poke implements the cartMapper interface -func (cart *mnetwork) Poke(addr uint16, data uint8) error { - return errors.New(errors.UnpokeableAddress, addr) -} - // Patch implements the cartMapper interface -func (cart *mnetwork) Patch(addr uint16, data uint8) error { - return errors.New(errors.UnpatchableCartType, cart.mappingID) +func (cart *mnetwork) Patch(offset int, data uint8) error { + if offset >= cart.bankSize*len(cart.banks) { + return errors.New(errors.CartridgePatchOOB, offset) + } + + bank := int(offset) / cart.bankSize + offset = offset % cart.bankSize + cart.banks[bank][offset] = data + return nil } // Listen implements the cartMapper interface -func (cart *mnetwork) Listen(addr uint16, data uint8) { +func (cart *mnetwork) Listen(_ uint16, _ uint8) { } // Step implements the cartMapper interface diff --git a/hardware/memory/cartridge/mapper_parkerbros.go b/hardware/memory/cartridge/mapper_parkerbros.go index 9f7604f6..2f6a8114 100644 --- a/hardware/memory/cartridge/mapper_parkerbros.go +++ b/hardware/memory/cartridge/mapper_parkerbros.go @@ -62,7 +62,8 @@ type parkerBros struct { mappingID string description string - banks [][]uint8 + bankSize int + banks [][]uint8 // parker bros. cartridges divide memory into 4 segments // o the last segment always points to the last bank @@ -74,21 +75,22 @@ type parkerBros struct { } func newparkerBros(data []byte) (cartMapper, error) { - const bankSize = 1024 + cart := &parkerBros{ + description: "parker bros", + mappingID: "E0", + bankSize: 1024, + } - cart := &parkerBros{} - cart.description = "parker bros" - cart.mappingID = "E0" cart.banks = make([][]uint8, cart.NumBanks()) - if len(data) != bankSize*cart.NumBanks() { + if len(data) != cart.bankSize*cart.NumBanks() { return nil, errors.New(errors.CartridgeError, fmt.Sprintf("%s: wrong number of bytes in the cartridge file", cart.mappingID)) } for k := 0; k < cart.NumBanks(); k++ { - cart.banks[k] = make([]uint8, bankSize) - offset := k * bankSize - copy(cart.banks[k], data[offset:offset+bankSize]) + cart.banks[k] = make([]uint8, cart.bankSize) + offset := k * cart.bankSize + copy(cart.banks[k], data[offset:offset+cart.bankSize]) } cart.Initialise() @@ -130,11 +132,24 @@ func (cart *parkerBros) Read(addr uint16) (uint8, error) { } // Write implements the cartMapper interface -func (cart *parkerBros) Write(addr uint16, data uint8) error { +func (cart *parkerBros) Write(addr uint16, data uint8, poke bool) error { if cart.bankSwitchOnAccess(addr) { return nil } - return errors.New(errors.BusError, addr) + + if poke { + if addr >= 0x0000 && addr <= 0x03ff { + cart.banks[cart.segment[0]][addr&0x3dd] = data + } else if addr >= 0x0400 && addr <= 0x07ff { + cart.banks[cart.segment[1]][addr&0x3dd] = data + } else if addr >= 0x0800 && addr <= 0x0bff { + cart.banks[cart.segment[2]][addr&0x3dd] = data + } else if addr >= 0x0c00 && addr <= 0x0fff { + cart.banks[cart.segment[3]][addr&0x3dd] = data + } + } + + return errors.New(errors.MemoryBusError, addr) } func (cart *parkerBros) bankSwitchOnAccess(addr uint16) bool { @@ -247,18 +262,20 @@ func (cart *parkerBros) RestoreState(state interface{}) error { return nil } -// Poke implements the cartMapper interface -func (cart *parkerBros) Poke(addr uint16, data uint8) error { - return errors.New(errors.UnpokeableAddress, addr) -} - // Patch implements the cartMapper interface -func (cart *parkerBros) Patch(addr uint16, data uint8) error { - return errors.New(errors.UnpatchableCartType, cart.mappingID) +func (cart *parkerBros) Patch(offset int, data uint8) error { + if offset >= cart.bankSize*len(cart.banks) { + return errors.New(errors.CartridgePatchOOB, offset) + } + + bank := int(offset) / cart.bankSize + offset = offset % cart.bankSize + cart.banks[bank][offset] = data + return nil } // Listen implements the cartMapper interface -func (cart *parkerBros) Listen(addr uint16, data uint8) { +func (cart *parkerBros) Listen(_ uint16, _ uint8) { } // Step implements the cartMapper interface diff --git a/hardware/memory/cartridge/mapper_tigervision.go b/hardware/memory/cartridge/mapper_tigervision.go index 3742f3fe..d2313d88 100644 --- a/hardware/memory/cartridge/mapper_tigervision.go +++ b/hardware/memory/cartridge/mapper_tigervision.go @@ -60,7 +60,8 @@ type tigervision struct { mappingID string description string - banks [][]uint8 + bankSize int + banks [][]uint8 // tigervision cartridges divide memory into two 2k segments // o the last segment always points to the last bank @@ -74,27 +75,27 @@ 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) func newTigervision(data []byte) (cartMapper, error) { - const bankSize = 2048 + cart := &tigervision{ + description: "tigervision", + mappingID: "3F", + bankSize: 2048, + } - if len(data)%bankSize != 0 { + if len(data)%cart.bankSize != 0 { return nil, errors.New(errors.CartridgeError, "tigervision (3F): cartridge size must be multiple of 2048") } - numBanks := len(data) / bankSize - - cart := &tigervision{} - cart.description = "tigervision" - cart.mappingID = "3F" + numBanks := len(data) / cart.bankSize cart.banks = make([][]uint8, numBanks) - if len(data) != bankSize*numBanks { + if len(data) != cart.bankSize*numBanks { return nil, errors.New(errors.CartridgeError, fmt.Sprintf("%s: wrong number bytes in the cartridge file", cart.mappingID)) } for k := 0; k < numBanks; k++ { - cart.banks[k] = make([]uint8, bankSize) - offset := k * bankSize - copy(cart.banks[k], data[offset:offset+bankSize]) + cart.banks[k] = make([]uint8, cart.bankSize) + offset := k * cart.bankSize + copy(cart.banks[k], data[offset:offset+cart.bankSize]) } cart.Initialise() @@ -131,8 +132,15 @@ func (cart *tigervision) Read(addr uint16) (uint8, error) { } // Write implements the cartMapper interface -func (cart *tigervision) Write(addr uint16, data uint8) error { - return errors.New(errors.BusError, addr) +func (cart *tigervision) Write(addr uint16, data uint8, poke bool) error { + if poke { + if addr >= 0x0000 && addr <= 0x07ff { + cart.banks[cart.segment[0]][addr&0x07ff] = data + } else if addr >= 0x0800 && addr <= 0x0fff { + cart.banks[cart.segment[1]][addr&0x07ff] = data + } + } + return errors.New(errors.MemoryBusError, addr) } // NumBanks implements the cartMapper interface @@ -172,14 +180,16 @@ func (cart *tigervision) RestoreState(state interface{}) error { return nil } -// Poke implements the cartMapper interface -func (cart *tigervision) Poke(addr uint16, data uint8) error { - return errors.New(errors.UnpokeableAddress, addr) -} - // Patch implements the cartMapper interface -func (cart *tigervision) Patch(addr uint16, data uint8) error { - return errors.New(errors.UnpatchableCartType, cart.mappingID) +func (cart *tigervision) Patch(offset int, data uint8) error { + if offset >= cart.bankSize*len(cart.banks) { + return errors.New(errors.CartridgePatchOOB, offset) + } + + bank := int(offset) / cart.bankSize + offset = offset % cart.bankSize + cart.banks[bank][offset] = data + return nil } // Listen implements the cartMapper interface diff --git a/hardware/memory/chip.go b/hardware/memory/chip.go index dbfce613..d87909e5 100644 --- a/hardware/memory/chip.go +++ b/hardware/memory/chip.go @@ -108,7 +108,7 @@ func (area *ChipMemory) Read(address uint16) (uint8, error) { // do not allow reads from memory that do not have symbol name if _, ok := addresses.CanonicalReadSymbols[address]; !ok { - return 0, errors.New(errors.BusError, address) + return 0, errors.New(errors.MemoryBusError, address) } return area.memory[address^area.origin], nil @@ -116,14 +116,15 @@ func (area *ChipMemory) Read(address uint16) (uint8, error) { // Write is an implementation of memory.CPUBus. Address must be normalised. func (area *ChipMemory) Write(address uint16, data uint8) error { - // check that the last write to this memory area has been serviced + // check that the last write to this memory area has been serviced. this + // shouldn't ever happen. if area.writeSignal { - return errors.New(errors.MemoryError, fmt.Sprintf("unserviced write to chip memory (%s)", addresses.Write[area.writeAddress])) + panic(fmt.Sprintf("unserviced write to chip memory (%s)", addresses.Write[area.writeAddress])) } // do not allow writes to memory that do not have symbol name if _, ok := addresses.CanonicalWriteSymbols[address]; !ok { - return errors.New(errors.BusError, address) + return errors.New(errors.MemoryBusError, address) } // signal the chips that their chip memory has been written to diff --git a/hardware/memory/memory.go b/hardware/memory/memory.go index d237165a..7b96a37c 100644 --- a/hardware/memory/memory.go +++ b/hardware/memory/memory.go @@ -22,7 +22,6 @@ package memory import ( "math/rand" - "github.com/jetsetilly/gopher2600/errors" "github.com/jetsetilly/gopher2600/hardware/memory/addresses" "github.com/jetsetilly/gopher2600/hardware/memory/bus" "github.com/jetsetilly/gopher2600/hardware/memory/cartridge" @@ -83,10 +82,6 @@ func NewVCSMemory() (*VCSMemory, error) { mem.RAM = newRAM() mem.Cart = cartridge.NewCartridge() - if mem.RIOT == nil || mem.TIA == nil || mem.RAM == nil || mem.Cart == nil { - return nil, errors.New(errors.MemoryError, "cannot create memory areas") - } - // create the memory map by associating all addresses in each memory area // with that area for i := memorymap.OriginTIA; i <= memorymap.MemtopTIA; i++ { @@ -109,19 +104,19 @@ func NewVCSMemory() (*VCSMemory, error) { } // GetArea returns the actual memory of the specified area type -func (mem *VCSMemory) GetArea(area memorymap.Area) (bus.DebuggerBus, error) { +func (mem *VCSMemory) GetArea(area memorymap.Area) bus.DebuggerBus { switch area { case memorymap.TIA: - return mem.TIA, nil + return mem.TIA case memorymap.RAM: - return mem.RAM, nil + return mem.RAM case memorymap.RIOT: - return mem.RIOT, nil + return mem.RIOT case memorymap.Cartridge: - return mem.Cart, nil + return mem.Cart } - return nil, errors.New(errors.MemoryError, "area not mapped correctly") + panic("memory areas are not mapped correctly") } // read maps an address to the normalised for all memory areas. @@ -129,10 +124,7 @@ func (mem *VCSMemory) read(address uint16, zeroPage bool) (uint8, error) { // optimisation: called a lot. pointer to VCSMemory to prevent duffcopy ma, ar := memorymap.MapAddress(address, true) - area, err := mem.GetArea(ar) - if err != nil { - return 0, err - } + area := mem.GetArea(ar) data, err := area.(bus.CPUBus).Read(ma) @@ -187,10 +179,7 @@ func (mem *VCSMemory) ReadZeroPage(address uint8) (uint8, error) { // processed by the correct memory areas. func (mem *VCSMemory) Write(address uint16, data uint8) error { ma, ar := memorymap.MapAddress(address, false) - area, err := mem.GetArea(ar) - if err != nil { - return err - } + area := mem.GetArea(ar) mem.LastAccessAddress = ma mem.LastAccessWrite = true diff --git a/patch/doc.go b/patch/doc.go index ab2bf654..7828dd08 100644 --- a/patch/doc.go +++ b/patch/doc.go @@ -42,12 +42,12 @@ // Rules: // // 1. Lines beginning with a hyphen or white space are ignored -// 2. Addresses and values are expressed in hex (case-insensitive) -// 3. Values and addresses are separated by a colon -// 4. Multiple values on a line are poked into consecutive addresses, starting -// from the address value +// 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 addresses are expressed with origin zero and have no relationship +// 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 // applied to the cartridge file image. The cartridge mapper handles the VCS // memory side of things. diff --git a/patch/patch.go b/patch/patch.go index ba9dbdfb..1ddf1ec7 100644 --- a/patch/patch.go +++ b/patch/patch.go @@ -86,7 +86,7 @@ func CartridgeMemory(mem *cartridge.Cartridge, patchFile string) (bool, error) { pokeLine := strings.Split(lines[i], pokeLineSeparator) - // ignore any lines that don't match the required [address: values...] format + // ignore any lines that don't match the required [offset: values...] format if len(pokeLine) != 2 { continue // for loop } @@ -95,8 +95,8 @@ func CartridgeMemory(mem *cartridge.Cartridge, patchFile string) (bool, error) { pokeLine[0] = strings.TrimSpace(pokeLine[0]) pokeLine[1] = strings.TrimSpace(pokeLine[1]) - // parse address - address, err := strconv.ParseInt(pokeLine[0], 16, 16) + // parse offset + offset, err := strconv.ParseInt(pokeLine[0], 16, 16) if err != nil { continue // for loop } @@ -120,14 +120,14 @@ func CartridgeMemory(mem *cartridge.Cartridge, patchFile string) (bool, error) { } // patch memory - err = mem.Patch(uint16(address), uint8(v)) + err = mem.Patch(int(offset), uint8(v)) if err != nil { return patched, errors.New(errors.PatchError, err) } patched = true - // advance address - address++ + // advance offset + offset++ } }