Cartridge.java

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
Location : read
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:readDelegatesToMapper()]
replaced int return with 0 for com/rox/cartridge/Cartridge::read → KILLED

39

1.1
Location : write
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:writeWithNoListenerRegisteredIsStillFine()]
removed call to com/rox/cartridge/Mapper::write → KILLED

40

1.1
Location : write
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:onPrgRamWriteDoesNotFireForAWriteAt0x8000OrAbove()]
changed conditional boundary → KILLED

2.2
Location : write
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:onPrgRamWriteFiresForAWriteBelow0x8000()]
negated conditional → KILLED

41

1.1
Location : write
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:onPrgRamWriteFiresForAWriteBelow0x8000()]
removed call to java/lang/Runnable::run → KILLED

53

1.1
Location : writePrgRamWithoutSaving
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:writePrgRamWithoutSavingWritesThroughTheMapperButDoesNotNotify()]
negated conditional → KILLED

2.2
Location : writePrgRamWithoutSaving
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:writePrgRamWithoutSavingWritesThroughTheMapperButDoesNotNotify()]
negated conditional → KILLED

3.3
Location : writePrgRamWithoutSaving
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:writePrgRamWithoutSavingRefusesAnythingButPrgRam()]
changed conditional boundary → KILLED

4.4
Location : writePrgRamWithoutSaving
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:writePrgRamWithoutSavingWritesThroughTheMapperButDoesNotNotify()]
changed conditional boundary → KILLED

56

1.1
Location : writePrgRamWithoutSaving
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:writePrgRamWithoutSavingWritesThroughTheMapperButDoesNotNotify()]
removed call to com/rox/cartridge/Mapper::write → KILLED

65

1.1
Location : prgRam
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:prgRamDelegatesToMapper()]
replaced return value with null for com/rox/cartridge/Cartridge::prgRam → KILLED

69

1.1
Location : restorePrgRam
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:restorePrgRamDelegatesToMapper()]
removed call to com/rox/cartridge/Mapper::restorePrgRam → KILLED

74

1.1
Location : snapshot
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:snapshotDelegatesToMapper()]
replaced return value with null for com/rox/cartridge/Cartridge::snapshot → KILLED

79

1.1
Location : checkRestorable
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:checkRestorableDelegatesToMapper()]
removed call to com/rox/cartridge/Mapper::checkRestorable → KILLED

84

1.1
Location : restore
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:restoreDelegatesToMapper()]
removed call to com/rox/cartridge/Mapper::restore → KILLED

88

1.1
Location : readChr
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:readChrDelegatesToMapper()]
replaced int return with 0 for com/rox/cartridge/Cartridge::readChr → KILLED

92

1.1
Location : writeChr
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:writeChrDelegatesToMapper()]
removed call to com/rox/cartridge/Mapper::writeChr → KILLED

96

1.1
Location : nametableMirroring
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:nametableMirroringDelegatesToMapper()]
replaced return value with null for com/rox/cartridge/Cartridge::nametableMirroring → KILLED

101

1.1
Location : isIrqAsserted
Killed by : com.rox.NESTest.[engine:junit-jupiter]/[class:com.rox.NESTest]/[method:vblankNmiDoesNotFireBeforeTheRealVblankEdge()]
replaced boolean return with true for com/rox/cartridge/Cartridge::isIrqAsserted → KILLED

2.2
Location : isIrqAsserted
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:isIrqAssertedDelegatesToMapper()]
replaced boolean return with false for com/rox/cartridge/Cartridge::isIrqAsserted → KILLED

105

1.1
Location : rom
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:romReturnsTheParsedINesRom()]
replaced return value with null for com/rox/cartridge/Cartridge::rom → KILLED

110

1.1
Location : debugState
Killed by : com.rox.cartridge.CartridgeTest.[engine:junit-jupiter]/[class:com.rox.cartridge.CartridgeTest]/[method:debugStateDelegatesToMapper()]
replaced return value with Collections.emptyMap for com/rox/cartridge/Cartridge::debugState → KILLED

Active mutators

Tests examined


Report generated by PIT 1.22.1