DebugCapture.java

1
package com.rox;
2
3
import com.rox.cartridge.Cartridge;
4
import com.rox.cpu.mos6502.assembler.Disassembler;
5
import com.rox.debug.report.DebugReport;
6
import com.rox.mem.NESMemoryBus;
7
import com.rox.save.SystemSnapshot;
8
9
import java.time.LocalDateTime;
10
import java.util.function.IntUnaryOperator;
11
12
/**
13
 * Builds a {@link DebugReport} from a paused {@link NES} - the {@code NES}-touching glue for a flagged
14
 * issue, kept in this package (like {@code PpuDebugViewerDemo}) so it can use {@code NES}'s
15
 * package-private component accessors without widening them.
16
 */
17
final class DebugCapture {
18
    static final int UPCOMING_INSTRUCTION_COUNT = 10;
19
    /**
20
     * Stands in for any {@code $2000-$4017} byte when disassembling: reading those registers for real
21
     * has side effects (clearing vblank, advancing {@code $2007}'s buffer, shifting controller bits).
22
     * {@code $FF} isn't a modeled opcode, so code there shows as {@code ??? ($FF)} rather than
23
     * plausible-looking instructions.
24
     */
25
    static final int REGISTER_PLACEHOLDER_BYTE = 0xFF;
26
    /** What {@link NESMemoryBus} itself returns for the unmapped {@code $4018-$5FFF}. */
27
    static final int UNMAPPED_BYTE = 0;
28
29
    private DebugCapture(){
30
    }
31
32
    /**
33
     * @param lastFrame the last complete frame shown, or {@code null} if none yet
34
     * @throws IllegalStateException if {@code nes} is running and not paused
35
     */
36
    static DebugReport capture(final NES nes, final String romName, final int[] lastFrame, final LocalDateTime capturedAt){
37
        final SystemSnapshot snapshot = nes.captureSnapshot();
38
        final IntUnaryOperator peek = sideEffectFreePeek(snapshot.ram(), nes.cartridge());
39 1 1. capture : replaced return value with null for com/rox/DebugCapture::capture → KILLED
        return new DebugReport(capturedAt, romName, "", lastFrame, nes.ppu().rgbFramebuffer(), snapshot,
40
                nes.cartridge().debugState(),
41
                Disassembler.disassembleForward(peek, snapshot.cpu().pc(), UPCOMING_INSTRUCTION_COUNT));
42
    }
43
44
    /**
45
     * Mirrors {@link NESMemoryBus}'s routing - including RAM mirroring and the unmapped
46
     * {@code $4018-$5FFF} - minus the registers whose reads have side effects.
47
     */
48
    static IntUnaryOperator sideEffectFreePeek(final int[] ram, final Cartridge cartridge){
49 2 1. lambda$sideEffectFreePeek$0 : replaced int return with 0 for com/rox/DebugCapture::lambda$sideEffectFreePeek$0 → KILLED
2. sideEffectFreePeek : replaced return value with null for com/rox/DebugCapture::sideEffectFreePeek → KILLED
        return sideEffectFreePeek(ramAddress -> ram[ramAddress], cartridge);
50
    }
51
52
    /**
53
     * As {@link #sideEffectFreePeek(int[], Cartridge)}, but reading RAM through {@code ramRead} (given an
54
     * already-mirrored {@code $0000-$07FF} address) - e.g. live RAM, from the clock thread itself.
55
     */
56
    static IntUnaryOperator sideEffectFreePeek(final IntUnaryOperator ramRead, final Cartridge cartridge){
57 1 1. sideEffectFreePeek : replaced return value with null for com/rox/DebugCapture::sideEffectFreePeek → KILLED
        return address -> {
58 2 1. lambda$sideEffectFreePeek$1 : negated conditional → KILLED
2. lambda$sideEffectFreePeek$1 : changed conditional boundary → KILLED
            if (address <= NESMemoryBus.CPU_RAM_END_ADDRESS){
59 2 1. lambda$sideEffectFreePeek$1 : replaced int return with 0 for com/rox/DebugCapture::lambda$sideEffectFreePeek$1 → KILLED
2. lambda$sideEffectFreePeek$1 : Replaced bitwise AND with OR → KILLED
                return ramRead.applyAsInt(address & NESMemoryBus.CPU_RAM_MIRROR_MASK);
60
            }
61 2 1. lambda$sideEffectFreePeek$1 : changed conditional boundary → KILLED
2. lambda$sideEffectFreePeek$1 : negated conditional → KILLED
            if (address <= NESMemoryBus.IO_END_ADDRESS){
62 1 1. lambda$sideEffectFreePeek$1 : replaced int return with 0 for com/rox/DebugCapture::lambda$sideEffectFreePeek$1 → KILLED
                return REGISTER_PLACEHOLDER_BYTE;
63
            }
64 2 1. lambda$sideEffectFreePeek$1 : changed conditional boundary → KILLED
2. lambda$sideEffectFreePeek$1 : negated conditional → KILLED
            if (address >= NESMemoryBus.CARTRIDGE_START_ADDRESS){
65 1 1. lambda$sideEffectFreePeek$1 : replaced int return with 0 for com/rox/DebugCapture::lambda$sideEffectFreePeek$1 → KILLED
                return cartridge.read(address); //PRG-RAM/PRG-ROM reads have no side effects on any mapper
66
            }
67
            return UNMAPPED_BYTE;
68
        };
69
    }
70
}

Mutations

39

1.1
Location : capture
Killed by : com.rox.DebugCaptureTest.[engine:junit-jupiter]/[class:com.rox.DebugCaptureTest]/[method:captureDisassemblesForwardFromTheCpusPc()]
replaced return value with null for com/rox/DebugCapture::capture → KILLED

49

1.1
Location : lambda$sideEffectFreePeek$0
Killed by : com.rox.DebugCaptureTest.[engine:junit-jupiter]/[class:com.rox.DebugCaptureTest]/[test-template:peekRoutesLikeTheBusButNeverTouchesRegisters(java.lang.String, java.lang.String)]/[test-template-invocation:#2]
replaced int return with 0 for com/rox/DebugCapture::lambda$sideEffectFreePeek$0 → KILLED

2.2
Location : sideEffectFreePeek
Killed by : com.rox.DebugCaptureTest.[engine:junit-jupiter]/[class:com.rox.DebugCaptureTest]/[test-template:peekRoutesLikeTheBusButNeverTouchesRegisters(java.lang.String, java.lang.String)]/[test-template-invocation:#9]
replaced return value with null for com/rox/DebugCapture::sideEffectFreePeek → KILLED

57

1.1
Location : sideEffectFreePeek
Killed by : com.rox.DebugCaptureTest.[engine:junit-jupiter]/[class:com.rox.DebugCaptureTest]/[test-template:peekRoutesLikeTheBusButNeverTouchesRegisters(java.lang.String, java.lang.String)]/[test-template-invocation:#7]
replaced return value with null for com/rox/DebugCapture::sideEffectFreePeek → KILLED

58

1.1
Location : lambda$sideEffectFreePeek$1
Killed by : com.rox.DebugCaptureTest.[engine:junit-jupiter]/[class:com.rox.DebugCaptureTest]/[test-template:peekRoutesLikeTheBusButNeverTouchesRegisters(java.lang.String, java.lang.String)]/[test-template-invocation:#7]
negated conditional → KILLED

2.2
Location : lambda$sideEffectFreePeek$1
Killed by : com.rox.DebugCaptureTest.[engine:junit-jupiter]/[class:com.rox.DebugCaptureTest]/[test-template:peekRoutesLikeTheBusButNeverTouchesRegisters(java.lang.String, java.lang.String)]/[test-template-invocation:#4]
changed conditional boundary → KILLED

59

1.1
Location : lambda$sideEffectFreePeek$1
Killed by : com.rox.DebugCaptureTest.[engine:junit-jupiter]/[class:com.rox.DebugCaptureTest]/[test-template:peekRoutesLikeTheBusButNeverTouchesRegisters(java.lang.String, java.lang.String)]/[test-template-invocation:#2]
replaced int return with 0 for com/rox/DebugCapture::lambda$sideEffectFreePeek$1 → KILLED

2.2
Location : lambda$sideEffectFreePeek$1
Killed by : com.rox.DebugCaptureTest.[engine:junit-jupiter]/[class:com.rox.DebugCaptureTest]/[test-template:peekRoutesLikeTheBusButNeverTouchesRegisters(java.lang.String, java.lang.String)]/[test-template-invocation:#4]
Replaced bitwise AND with OR → KILLED

61

1.1
Location : lambda$sideEffectFreePeek$1
Killed by : com.rox.DebugCaptureTest.[engine:junit-jupiter]/[class:com.rox.DebugCaptureTest]/[test-template:peekRoutesLikeTheBusButNeverTouchesRegisters(java.lang.String, java.lang.String)]/[test-template-invocation:#8]
changed conditional boundary → KILLED

2.2
Location : lambda$sideEffectFreePeek$1
Killed by : com.rox.DebugCaptureTest.[engine:junit-jupiter]/[class:com.rox.DebugCaptureTest]/[test-template:peekRoutesLikeTheBusButNeverTouchesRegisters(java.lang.String, java.lang.String)]/[test-template-invocation:#9]
negated conditional → KILLED

62

1.1
Location : lambda$sideEffectFreePeek$1
Killed by : com.rox.DebugCaptureTest.[engine:junit-jupiter]/[class:com.rox.DebugCaptureTest]/[test-template:peekRoutesLikeTheBusButNeverTouchesRegisters(java.lang.String, java.lang.String)]/[test-template-invocation:#8]
replaced int return with 0 for com/rox/DebugCapture::lambda$sideEffectFreePeek$1 → KILLED

64

1.1
Location : lambda$sideEffectFreePeek$1
Killed by : com.rox.DebugCaptureTest.[engine:junit-jupiter]/[class:com.rox.DebugCaptureTest]/[test-template:peekRoutesLikeTheBusButNeverTouchesRegisters(java.lang.String, java.lang.String)]/[test-template-invocation:#11]
changed conditional boundary → KILLED

2.2
Location : lambda$sideEffectFreePeek$1
Killed by : com.rox.DebugCaptureTest.[engine:junit-jupiter]/[class:com.rox.DebugCaptureTest]/[test-template:peekRoutesLikeTheBusButNeverTouchesRegisters(java.lang.String, java.lang.String)]/[test-template-invocation:#11]
negated conditional → KILLED

65

1.1
Location : lambda$sideEffectFreePeek$1
Killed by : com.rox.DebugCaptureTest.[engine:junit-jupiter]/[class:com.rox.DebugCaptureTest]/[test-template:peekRoutesLikeTheBusButNeverTouchesRegisters(java.lang.String, java.lang.String)]/[test-template-invocation:#11]
replaced int return with 0 for com/rox/DebugCapture::lambda$sideEffectFreePeek$1 → KILLED

Active mutators

Tests examined


Report generated by PIT 1.22.1