moved Patch() from CartMapper to CartPatchable interface

this means that a mapper only needs to implement the Patch() if it makes
sense

mappers that don't need it have had the Patch function removed.
implemented function for SCABS and UA

corrected error messages for atari mappers - some messages weren't
referencing the correct atari mapper and simply stated "atari"
This commit is contained in:
JetSetIlly 2023-11-26 09:16:39 +00:00
parent 6bb531104c
commit 84ad23c03e
24 changed files with 90 additions and 102 deletions

View file

@ -143,11 +143,6 @@ func (cart *Ace) GetBank(_ uint16) mapper.BankInfo {
return mapper.BankInfo{Number: 0, IsRAM: false}
}
// Patch implements the mapper.CartMapper interface.
func (cart *Ace) Patch(_ int, _ uint8) error {
return fmt.Errorf("ACE: patching unsupported")
}
func (cart *Ace) runARM() bool {
// call arm once and then check for yield conditions
var cycles float32

View file

@ -149,12 +149,6 @@ func (cart *Cartridge) Poke(addr uint16, data uint8) error {
return cart.mapper.AccessVolatile(addr&memorymap.CartridgeBits, 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 int, data uint8) error {
return cart.mapper.Patch(offset, data)
}
// Read is an implementation of memory.CPUBus.
func (cart *Cartridge) Read(addr uint16) (uint8, uint8, error) {
return cart.mapper.Access(addr&memorymap.CartridgeBits, false)
@ -552,10 +546,18 @@ func (cart *Cartridge) CoProcExecutionState() coprocessor.CoProcExecutionState {
return coprocessor.CoProcExecutionState{}
}
// BusStuff implements the mapper.CartBusStuff interface.
// BusStuff implements the mapper.CartBusStuff interface
func (cart *Cartridge) BusStuff() (uint8, bool) {
if cart.hasBusStuff {
return cart.busStuff.BusStuff()
}
return 0, false
}
// Patch implements the mapper.CartPatchable interface
func (cart *Cartridge) Patch(offset int, data uint8) error {
if cart, ok := cart.mapper.(mapper.CartPatchable); ok {
return cart.Patch(offset, data)
}
return fmt.Errorf("cartridge is not patchable")
}

View file

@ -424,11 +424,6 @@ func (cart *cdf) GetBank(addr uint16) mapper.BankInfo {
}
}
// Patch implements the mapper.CartMapper interface.
func (cart *cdf) Patch(offset int, data uint8) error {
return fmt.Errorf("CDF: patching unsupported")
}
// AccessPassive implements the mapper.CartMapper interface.
func (cart *cdf) AccessPassive(addr uint16, data uint8) error {
return nil

View file

@ -682,11 +682,6 @@ func (cart *dpcPlus) GetBank(addr uint16) mapper.BankInfo {
}
}
// Patch implements the mapper.CartMapper interface.
func (cart *dpcPlus) Patch(offset int, data uint8) error {
return fmt.Errorf("DPC+: patching unsupported")
}
// AccessPassive implements the mapper.CartMapper interface.
func (cart *dpcPlus) AccessPassive(addr uint16, data uint8) error {
return nil

View file

@ -275,11 +275,6 @@ func (cart *Elf) GetBank(_ uint16) mapper.BankInfo {
return mapper.BankInfo{Number: 0, IsRAM: false}
}
// Patch implements the mapper.CartMapper interface.
func (cart *Elf) Patch(_ int, _ uint8) error {
return fmt.Errorf("ELF: patching unsupported")
}
func (cart *Elf) runARM(addr uint16) bool {
if cart.mem.stream.active {
// do nothing with the ARM if the byte stream is draining

View file

@ -83,12 +83,6 @@ type CartMapper interface {
// at the rate specified.
Step(clock float32)
// patch differs from write/poke in that it alters the data as though it
// was being read from disk. that is, the offset is measured from the start
// of the file. the cartmapper must translate the offset and update the
// correct data structure as appropriate.
Patch(offset int, data uint8) error
// return copies of all banks in the cartridge. the disassembly process
// uses this to access cartridge data freely and without affecting the
// state of the cartridge.
@ -351,3 +345,13 @@ type CartROMDump interface {
type CartBusStuff interface {
BusStuff() (uint8, bool)
}
// CartPatchable is implemented by cartridge mappers than can have their binary
// patched as part of the load process
type CartPatchable interface {
// patch is different to 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
}

View file

@ -169,7 +169,7 @@ func (cart *m3e) GetBank(addr uint16) mapper.BankInfo {
return mapper.BankInfo{Number: cart.state.segment[1], IsRAM: cart.state.segmentIsRAM[1], IsSegmented: true, Segment: 1}
}
// Patch implements the mapper.CartMapper interface.
// Patch implements the mapper.CartPatchable interface
func (cart *m3e) Patch(offset int, data uint8) error {
if offset >= cart.bankSize*len(cart.banks) {
return fmt.Errorf("3E: patch offset too high (%d)", offset)

View file

@ -211,7 +211,7 @@ func (cart *m3ePlus) GetBank(addr uint16) mapper.BankInfo {
return mapper.BankInfo{Number: cart.state.segment[seg], IsSegmented: true, Segment: seg}
}
// Patch implements the mapper.CartMapper interface.
// Patch implements the mapper.CartPatchable interface
func (cart *m3ePlus) Patch(offset int, data uint8) error {
if offset >= cart.bankSize*len(cart.banks) {
return fmt.Errorf("3E+: patch offset too high (%d)", offset)

View file

@ -113,19 +113,19 @@ func hasEmptyArea(d []uint8) bool {
func (cart *atari) ROMDump(filename string) error {
f, err := os.Create(filename)
if err != nil {
return fmt.Errorf("atari: %w", err)
return fmt.Errorf("%s: %w", cart.mappingID, err)
}
defer func() {
err := f.Close()
if err != nil {
logger.Logf("atari", err.Error())
logger.Logf("%s", cart.mappingID, err.Error())
}
}()
for _, b := range cart.banks {
_, err := f.Write(b)
if err != nil {
return fmt.Errorf("atari: %w", err)
return fmt.Errorf("%s: %w", cart.mappingID, err)
}
}
@ -212,10 +212,10 @@ func (cart *atari) accessVolatile(addr uint16, data uint8, poke bool) error {
return nil
}
// Patch implements the mapper.CartMapper interface.
// Patch implements the mapper.CartPatchable interface
func (cart *atari) Patch(offset int, data uint8) error {
if offset >= cart.bankSize*len(cart.banks) {
return fmt.Errorf("atari: patch offset too high (%d)", offset)
return fmt.Errorf("%s: patch offset too high (%d)", cart.mappingID, offset)
}
bank := offset / cart.bankSize

View file

@ -191,7 +191,7 @@ func (cart *cbs) GetBank(addr uint16) mapper.BankInfo {
return mapper.BankInfo{Number: cart.state.bank, IsRAM: addr <= 0x00ff}
}
// Patch implements the mapper.CartMapper interface.
// Patch implements the mapper.CartPatchable interface
func (cart *cbs) Patch(offset int, data uint8) error {
if offset >= cart.bankSize*len(cart.banks) {
return fmt.Errorf("FA: patch offset too high (%d)", offset)

View file

@ -147,7 +147,7 @@ func (cart *commavid) GetBank(addr uint16) mapper.BankInfo {
return mapper.BankInfo{Number: 0, IsRAM: addr <= 0x07ff}
}
// Patch implements the mapper.CartMapper interface.
// Patch implements the mapper.CartPatchable interface
func (cart *commavid) Patch(offset int, data uint8) error {
if offset >= cart.bankSize {
return fmt.Errorf("CV: patch offset too high (%d)", offset)

View file

@ -219,7 +219,7 @@ func (cart *df) GetBank(addr uint16) mapper.BankInfo {
return mapper.BankInfo{Number: cart.state.bank, IsRAM: addr <= 0x00ff}
}
// Patch implements the mapper.CartMapper interface.
// Patch implements the mapper.CartPatchable interface
func (cart *df) Patch(offset int, data uint8) error {
if offset >= cart.bankSize*len(cart.banks) {
return fmt.Errorf("DF: patch offset too high (%d)", offset)

View file

@ -296,7 +296,7 @@ func (cart *dpc) GetBank(addr uint16) mapper.BankInfo {
return mapper.BankInfo{Number: cart.state.bank, IsRAM: false}
}
// Patch implements the mapper.CartMapper interface.
// Patch implements the mapper.CartPatchable interface
func (cart *dpc) Patch(offset int, data uint8) error {
if offset >= cart.bankSize*len(cart.banks)+len(cart.static.data) {
return fmt.Errorf("DPC: patch offset too high (%d)", offset)

View file

@ -72,11 +72,6 @@ func (cart *ejected) GetBank(_ uint16) mapper.BankInfo {
return mapper.BankInfo{Number: 0, IsRAM: false}
}
// Patch implements the mapper.CartMapper interface.
func (cart *ejected) Patch(_ int, _ uint8) error {
return Ejected
}
// AccessPassive implements the mapper.CartMapper interface.
func (cart *ejected) AccessPassive(_ uint16, _ uint8) error {
return nil

View file

@ -308,7 +308,7 @@ func (cart *mnetwork) GetBank(addr uint16) mapper.BankInfo {
return mapper.BankInfo{Number: cart.NumBanks() - 1, IsRAM: false, IsSegmented: true, Segment: 1}
}
// Patch implements the mapper.CartMapper interface.
// Patch implements the mapper.CartPatchable interface.
func (cart *mnetwork) Patch(offset int, data uint8) error {
if offset >= cart.bankSize*len(cart.banks) {
return fmt.Errorf("E7: patch offset too high (%d)", offset)

View file

@ -233,7 +233,7 @@ func (cart *parkerBros) GetBank(addr uint16) mapper.BankInfo {
return mapper.BankInfo{Number: cart.state.segment[seg], IsRAM: false, IsSegmented: true, Segment: seg}
}
// Patch implements the mapper.CartMapper interface.
// Patch implements the mapper.CartPatchable interface.
func (cart *parkerBros) Patch(offset int, data uint8) error {
if offset >= cart.bankSize*len(cart.banks) {
return fmt.Errorf("E0: patch offset too high (%d)", offset)

View file

@ -103,11 +103,6 @@ func (cart *scabs) GetBank(_ uint16) mapper.BankInfo {
return mapper.BankInfo{Number: cart.state.bank, IsRAM: false}
}
// Patch implements the mapper.CartMapper interface.
func (cart *scabs) Patch(_ int, _ uint8) error {
return nil
}
// AccessPassive implements the mapper.CartMapper interface.
func (cart *scabs) AccessPassive(addr uint16, data uint8) error {
// "[...] it will be noted that JSR instruction is always followed by an
@ -181,6 +176,18 @@ func (cart *scabs) CopyBanks() []mapper.BankContent {
return c
}
// Patch implements the mapper.CartPatchable interface
func (cart *scabs) Patch(offset int, data uint8) error {
if offset >= cart.bankSize*len(cart.banks) {
return fmt.Errorf("FE: patch offset too high (%d)", offset)
}
bank := offset / cart.bankSize
offset %= cart.bankSize
cart.banks[bank][offset] = data
return nil
}
type scabsState struct {
bank int
bankSwitch int

View file

@ -121,7 +121,7 @@ func (cart *superbank) GetBank(addr uint16) mapper.BankInfo {
return mapper.BankInfo{Number: cart.state.bank, IsRAM: false}
}
// Patch implements the mapper.CartMapper interface.
// Patch implements the mapper.CartPatchable interface.
func (cart *superbank) Patch(offset int, data uint8) error {
if offset >= cart.bankSize*len(cart.banks) {
return fmt.Errorf("SB: patch offset too high (%d)", offset)

View file

@ -148,7 +148,7 @@ func (cart *tigervision) GetBank(addr uint16) mapper.BankInfo {
return mapper.BankInfo{Number: cart.state.segment[1], IsRAM: false, IsSegmented: true, Segment: 1}
}
// Patch implements the mapper.CartMapper interface.
// Patch implements the mapper.CartPatchable interface.
func (cart *tigervision) Patch(offset int, data uint8) error {
if offset >= cart.bankSize*len(cart.banks) {
return fmt.Errorf("3F: patch offset too high (%d)", offset)

View file

@ -121,11 +121,6 @@ func (cart *ua) GetBank(addr uint16) mapper.BankInfo {
return mapper.BankInfo{Number: cart.bank}
}
// Patch implements the mapper.CartMapper interface
func (cart *ua) Patch(offset int, data uint8) error {
return fmt.Errorf("UA: patching unsupported")
}
// AccessPassive implements the mapper.CartMapper interface
func (cart *ua) AccessPassive(addr uint16, data uint8) error {
switch addr & 0x1260 {
@ -160,3 +155,15 @@ func (cart *ua) CopyBanks() []mapper.BankContent {
}
return c
}
// Patch implements the mapper.CartPatchable interface
func (cart *ua) Patch(offset int, data uint8) error {
if offset >= cart.bankSize*len(cart.banks) {
return fmt.Errorf("UA: patch offset too high (%d)", offset)
}
bank := offset / cart.bankSize
offset %= cart.bankSize
cart.banks[bank][offset] = data
return nil
}

View file

@ -374,11 +374,6 @@ func (cart *Moviecart) AccessPassive(addr uint16, data uint8) error {
func (cart *Moviecart) Step(clock float32) {
}
// Patch implements the mapper.CartMapper interface.
func (cart *Moviecart) Patch(offset int, data uint8) error {
return nil
}
// CopyBanks implements the mapper.CartMapper interface.
func (cart *Moviecart) CopyBanks() []mapper.BankContent {
// note that as it is, this will be a copy of the core program without any

View file

@ -239,11 +239,6 @@ func (cart *PlusROM) GetBank(addr uint16) mapper.BankInfo {
return cart.state.child.GetBank(addr)
}
// Patch implements the mapper.CartMapper interface.
func (cart *PlusROM) Patch(offset int, data uint8) error {
return cart.state.child.Patch(offset, data)
}
// AccessPassive implements the mapper.CartMapper interface.
func (cart *PlusROM) AccessPassive(addr uint16, data uint8) error {
return cart.state.child.AccessPassive(addr, data)
@ -262,65 +257,73 @@ func (cart *PlusROM) CopyBanks() []mapper.BankContent {
// GetGetRegisters implements the mapper.CartRegistersBus interface.
func (cart *PlusROM) GetRegisters() mapper.CartRegisters {
if rb, ok := cart.state.child.(mapper.CartRegistersBus); ok {
return rb.GetRegisters()
if cart, ok := cart.state.child.(mapper.CartRegistersBus); ok {
return cart.GetRegisters()
}
return nil
}
// PutRegister implements the mapper.CartRegistersBus interface.
func (cart *PlusROM) PutRegister(register string, data string) {
if rb, ok := cart.state.child.(mapper.CartRegistersBus); ok {
rb.PutRegister(register, data)
if cart, ok := cart.state.child.(mapper.CartRegistersBus); ok {
cart.PutRegister(register, data)
}
}
// GetRAM implements the mapper.CartRAMbus interface.
func (cart *PlusROM) GetRAM() []mapper.CartRAM {
if rb, ok := cart.state.child.(mapper.CartRAMbus); ok {
return rb.GetRAM()
if cart, ok := cart.state.child.(mapper.CartRAMbus); ok {
return cart.GetRAM()
}
return nil
}
// PutRAM implements the mapper.CartRAMbus interface.
func (cart *PlusROM) PutRAM(bank int, idx int, data uint8) {
if rb, ok := cart.state.child.(mapper.CartRAMbus); ok {
rb.PutRAM(bank, idx, data)
if cart, ok := cart.state.child.(mapper.CartRAMbus); ok {
cart.PutRAM(bank, idx, data)
}
}
// GetStatic implements the mapper.CartStaticBus interface.
func (cart *PlusROM) GetStatic() mapper.CartStatic {
if sb, ok := cart.state.child.(mapper.CartStaticBus); ok {
return sb.GetStatic()
if cart, ok := cart.state.child.(mapper.CartStaticBus); ok {
return cart.GetStatic()
}
return nil
}
// PutStatic implements the mapper.CartStaticBus interface.
func (cart *PlusROM) PutStatic(segment string, idx int, data uint8) bool {
if sb, ok := cart.state.child.(mapper.CartStaticBus); ok {
return sb.PutStatic(segment, idx, data)
if cart, ok := cart.state.child.(mapper.CartStaticBus); ok {
return cart.PutStatic(segment, idx, data)
}
return true
}
// Rewind implements the mapper.CartTapeBus interface.
func (cart *PlusROM) Rewind() {
if sb, ok := cart.state.child.(mapper.CartTapeBus); ok {
sb.Rewind()
if cart, ok := cart.state.child.(mapper.CartTapeBus); ok {
cart.Rewind()
}
}
// GetTapeState implements the mapper.CartTapeBus interface.
func (cart *PlusROM) GetTapeState() (bool, mapper.CartTapeState) {
if sb, ok := cart.state.child.(mapper.CartTapeBus); ok {
return sb.GetTapeState()
if cart, ok := cart.state.child.(mapper.CartTapeBus); ok {
return cart.GetTapeState()
}
return false, mapper.CartTapeState{}
}
// Patch implements the mapper.CartPatchable interface.
func (cart *PlusROM) Patch(offset int, data uint8) error {
if cart, ok := cart.state.child.(mapper.CartPatchable); ok {
return cart.Patch(offset, data)
}
return nil
}
// RewindBoundary implements the mapper.CartRewindBoundary interface.
func (cart *PlusROM) RewindBoundary() bool {
if cart.rewindBoundary {

View file

@ -283,11 +283,6 @@ func (cart *Supercharger) GetBank(addr uint16) mapper.BankInfo {
panic("unknown banking method")
}
// Patch implements the mapper.CartMapper interface.
func (cart *Supercharger) Patch(_ int, _ uint8) error {
return fmt.Errorf("supercharger: not patchable")
}
// AccessPassive implements the mapper.CartMapper interface.
func (cart *Supercharger) AccessPassive(addr uint16, _ uint8) error {
cart.state.registers.transitionCount(addr)

View file

@ -35,7 +35,7 @@ const neoSeparator = ":"
// CartridgeMemory applies the contents of a patch file to cartridge memory.
// Currently, patch file must be in the patches sub-directory of the
// resource path (see paths package).
func CartridgeMemory(mem *cartridge.Cartridge, patchFile string) (bool, error) {
func CartridgeMemory(cart *cartridge.Cartridge, patchFile string) (bool, error) {
var err error
p, err := resources.JoinPath(patchPath, patchFile)
@ -71,7 +71,7 @@ func CartridgeMemory(mem *cartridge.Cartridge, patchFile string) (bool, error) {
// if first character is a hyphen then we'll assume this is a "neo" style
// patch file
if buffer[0] == neoComment {
err = neoStyle(mem, buffer)
err = neoStyle(cart, buffer)
if err != nil {
return false, fmt.Errorf("patch: %w", err)
}
@ -79,7 +79,7 @@ func CartridgeMemory(mem *cartridge.Cartridge, patchFile string) (bool, error) {
}
// otherwise assume it is a "cmp" style patch file
err = cmpStyle(mem, buffer)
err = cmpStyle(cart, buffer)
if err != nil {
return false, fmt.Errorf("patch: %w", err)
}
@ -87,7 +87,7 @@ func CartridgeMemory(mem *cartridge.Cartridge, patchFile string) (bool, error) {
}
// cmp -l <old_file> <new_file>.
func cmpStyle(mem *cartridge.Cartridge, buffer []byte) error {
func cmpStyle(cart *cartridge.Cartridge, buffer []byte) error {
// walk through lines
lines := strings.Split(string(buffer), "\n")
for i, s := range lines {
@ -125,13 +125,13 @@ func cmpStyle(mem *cartridge.Cartridge, buffer []byte) error {
}
// check that the patch is correct
o, _ := mem.Peek(uint16(offset))
o, _ := cart.Peek(uint16(offset))
if o != uint8(old) {
return fmt.Errorf("cmp: line %d: byte at offset %04x does not match expected byte (%02x instead of %02x)", i, offset, o, old)
}
// patch memory
err = mem.Patch(int(offset), uint8(patch))
err = cart.Patch(int(offset), uint8(patch))
if err != nil {
return fmt.Errorf("cmp: %w", err)
}
@ -139,7 +139,7 @@ func cmpStyle(mem *cartridge.Cartridge, buffer []byte) error {
return nil
}
func neoStyle(mem *cartridge.Cartridge, buffer []byte) error {
func neoStyle(cart *cartridge.Cartridge, buffer []byte) error {
// walk through lines
lines := strings.Split(string(buffer), "\n")
for i, s := range lines {
@ -188,7 +188,7 @@ func neoStyle(mem *cartridge.Cartridge, buffer []byte) error {
}
// patch memory
err = mem.Patch(int(offset), uint8(v))
err = cart.Patch(int(offset), uint8(v))
if err != nil {
return fmt.Errorf("neo: line %d: %w", i, err)
}