| 1 | package com.rox.cartridge; | |
| 2 | ||
| 3 | import com.rox.mem.MemoryBus; | |
| 4 | ||
| 5 | import java.util.Map; | |
| 6 | ||
| 7 | /** | |
| 8 | * A loaded ROM: the parsed {@link INesRom} plus whichever {@link Mapper} its header's mapper number | |
| 9 | * selects. Implements {@link MemoryBus} by delegating straight to the mapper - {@link INesRom} is | |
| 10 | * kept around for metadata (mirroring, mapper number) that later phases (PPU nametable mirroring, | |
| 11 | * a CLI printing what got loaded) need, not for address decoding. | |
| 12 | */ | |
| 13 | public final class Cartridge implements MemoryBus { | |
| 14 | //PRG-RAM on every currently-supported board (NROM, MMC1, MMC3) occupies $6000-$7FFF, PRG-ROM | |
| 15 | //starting at $8000 - safe to hardcode here rather than asking Mapper, since a Mapper's own | |
| 16 | //read/write are only ever called with addresses already known to be in $6000-$FFFF (see Mapper's | |
| 17 | //class doc) | |
| 18 | private static final int PRG_RAM_START_ADDRESS = 0x6000; | |
| 19 | private static final int PRG_ROM_START_ADDRESS = 0x8000; | |
| 20 | ||
| 21 | private final INesRom rom; | |
| 22 | private final Mapper mapper; | |
| 23 | //no-op default so cartridges nobody ever wires a listener onto (i.e. every non-battery-backed | |
| 24 | //cartridge) pay zero cost - set by BatterySaveManager for battery-backed carts only | |
| 25 | private Runnable onPrgRamWrite = () -> { }; | |
| 26 | ||
| 27 | public Cartridge(final INesRom rom, final Mapper mapper){ | |
| 28 | this.rom = rom; | |
| 29 | this.mapper = mapper; | |
| 30 | } | |
| 31 | ||
| 32 | @Override | |
| 33 | public int read(final int address){ | |
| 34 |
1
1. read : replaced int return with 0 for com/rox/cartridge/Cartridge::read → KILLED |
return mapper.read(address); |
| 35 | } | |
| 36 | ||
| 37 | @Override | |
| 38 | public void write(final int address, final int value){ | |
| 39 |
1
1. write : removed call to com/rox/cartridge/Mapper::write → KILLED |
mapper.write(address, value); |
| 40 |
2
1. write : changed conditional boundary → KILLED 2. write : negated conditional → KILLED |
if (address < PRG_ROM_START_ADDRESS){ |
| 41 |
1
1. write : removed call to java/lang/Runnable::run → KILLED |
onPrgRamWrite.run(); |
| 42 | } | |
| 43 | } | |
| 44 | ||
| 45 | /** | |
| 46 | * A debugging edit of PRG-RAM: the same write the game would make, minus the {@link #setOnPrgRamWrite} | |
| 47 | * notification - so a battery-backed save on disk only changes if the game itself writes afterwards. | |
| 48 | * | |
| 49 | * @throws IllegalArgumentException outside the {@code $6000-$7FFF} PRG-RAM window - a write anywhere | |
| 50 | * above it would be a mapper register write (e.g. a bank switch), not an edit | |
| 51 | */ | |
| 52 | public void writePrgRamWithoutSaving(final int address, final int value){ | |
| 53 |
4
1. writePrgRamWithoutSaving : negated conditional → KILLED 2. writePrgRamWithoutSaving : negated conditional → KILLED 3. writePrgRamWithoutSaving : changed conditional boundary → KILLED 4. writePrgRamWithoutSaving : changed conditional boundary → KILLED |
if (address < PRG_RAM_START_ADDRESS || address >= PRG_ROM_START_ADDRESS){ |
| 54 | throw new IllegalArgumentException(String.format("$%04X isn't PRG-RAM ($6000-$7FFF)", address)); | |
| 55 | } | |
| 56 |
1
1. writePrgRamWithoutSaving : removed call to com/rox/cartridge/Mapper::write → KILLED |
mapper.write(address, value); |
| 57 | } | |
| 58 | ||
| 59 | /** Notified (on whatever thread called {@link #write}) after every write to the {@code $6000-$7FFF} PRG-RAM window. */ | |
| 60 | public void setOnPrgRamWrite(final Runnable listener){ | |
| 61 | this.onPrgRamWrite = listener; | |
| 62 | } | |
| 63 | ||
| 64 | public int[] prgRam(){ | |
| 65 |
1
1. prgRam : replaced return value with null for com/rox/cartridge/Cartridge::prgRam → KILLED |
return mapper.prgRam(); |
| 66 | } | |
| 67 | ||
| 68 | public void restorePrgRam(final int[] prgRam){ | |
| 69 |
1
1. restorePrgRam : removed call to com/rox/cartridge/Mapper::restorePrgRam → KILLED |
mapper.restorePrgRam(prgRam); |
| 70 | } | |
| 71 | ||
| 72 | /** The mapper's complete mutable state, for a save state - see {@link Mapper#snapshot()}. */ | |
| 73 | public MapperSnapshot snapshot(){ | |
| 74 |
1
1. snapshot : replaced return value with null for com/rox/cartridge/Cartridge::snapshot → KILLED |
return mapper.snapshot(); |
| 75 | } | |
| 76 | ||
| 77 | /** See {@link Mapper#checkRestorable(MapperSnapshot)}. */ | |
| 78 | public void checkRestorable(final MapperSnapshot snapshot){ | |
| 79 |
1
1. checkRestorable : removed call to com/rox/cartridge/Mapper::checkRestorable → KILLED |
mapper.checkRestorable(snapshot); |
| 80 | } | |
| 81 | ||
| 82 | /** See {@link Mapper#restore(MapperSnapshot)}. */ | |
| 83 | public void restore(final MapperSnapshot snapshot){ | |
| 84 |
1
1. restore : removed call to com/rox/cartridge/Mapper::restore → KILLED |
mapper.restore(snapshot); |
| 85 | } | |
| 86 | ||
| 87 | public int readChr(final int address){ | |
| 88 |
1
1. readChr : replaced int return with 0 for com/rox/cartridge/Cartridge::readChr → KILLED |
return mapper.readChr(address); |
| 89 | } | |
| 90 | ||
| 91 | public void writeChr(final int address, final int value){ | |
| 92 |
1
1. writeChr : removed call to com/rox/cartridge/Mapper::writeChr → KILLED |
mapper.writeChr(address, value); |
| 93 | } | |
| 94 | ||
| 95 | public Mirroring nametableMirroring(){ | |
| 96 |
1
1. nametableMirroring : replaced return value with null for com/rox/cartridge/Cartridge::nametableMirroring → KILLED |
return mapper.nametableMirroring(); |
| 97 | } | |
| 98 | ||
| 99 | /** Whether the mapper (e.g. MMC3's scanline IRQ) is currently asserting an IRQ onto the CPU's IRQ line. */ | |
| 100 | public boolean isIrqAsserted(){ | |
| 101 |
2
1. isIrqAsserted : replaced boolean return with true for com/rox/cartridge/Cartridge::isIrqAsserted → KILLED 2. isIrqAsserted : replaced boolean return with false for com/rox/cartridge/Cartridge::isIrqAsserted → KILLED |
return mapper.isIrqAsserted(); |
| 102 | } | |
| 103 | ||
| 104 | public INesRom rom(){ | |
| 105 |
1
1. rom : replaced return value with null for com/rox/cartridge/Cartridge::rom → KILLED |
return rom; |
| 106 | } | |
| 107 | ||
| 108 | /** The mapper's current bank/IRQ register state, for a debug view - see {@link Mapper#debugState()}. */ | |
| 109 | public Map<String, String> debugState(){ | |
| 110 |
1
1. debugState : replaced return value with Collections.emptyMap for com/rox/cartridge/Cartridge::debugState → KILLED |
return mapper.debugState(); |
| 111 | } | |
| 112 | } | |
Mutations | ||
| 34 |
1.1 |
|
| 39 |
1.1 |
|
| 40 |
1.1 2.2 |
|
| 41 |
1.1 |
|
| 53 |
1.1 2.2 3.3 4.4 |
|
| 56 |
1.1 |
|
| 65 |
1.1 |
|
| 69 |
1.1 |
|
| 74 |
1.1 |
|
| 79 |
1.1 |
|
| 84 |
1.1 |
|
| 88 |
1.1 |
|
| 92 |
1.1 |
|
| 96 |
1.1 |
|
| 101 |
1.1 2.2 |
|
| 105 |
1.1 |
|
| 110 |
1.1 |