OpCodeTable.java

1
package com.rox.cpu.mos6502.assembler;
2
3
import com.rox.cpu.mos6502.MOS6502OpCode;
4
5
import java.util.EnumMap;
6
import java.util.HashMap;
7
import java.util.Map;
8
import java.util.Set;
9
10
/**
11
 * A mnemonic + {@link AddressingMode} -> {@link MOS6502OpCode} lookup, built once from
12
 * {@link MOS6502OpCode#values()} by splitting each constant's name on its first {@code _}
13
 * (e.g. {@code LDA_ABS_X} -> mnemonic {@code LDA}, suffix {@code ABS_X}) and mapping the
14
 * suffix to an {@link AddressingMode}.
15
 */
16
final class OpCodeTable {
17
18
    private static final Map<String, AddressingMode> MODE_BY_SUFFIX = Map.ofEntries(
19
            Map.entry("IMP", AddressingMode.IMPLIED),
20
            Map.entry("A", AddressingMode.ACCUMULATOR),
21
            Map.entry("I", AddressingMode.IMMEDIATE),
22
            Map.entry("Z", AddressingMode.ZERO_PAGE),
23
            Map.entry("Z_X", AddressingMode.ZERO_PAGE_X),
24
            Map.entry("Z_Y", AddressingMode.ZERO_PAGE_Y),
25
            Map.entry("ABS", AddressingMode.ABSOLUTE),
26
            Map.entry("ABS_X", AddressingMode.ABSOLUTE_X),
27
            Map.entry("ABS_Y", AddressingMode.ABSOLUTE_Y),
28
            Map.entry("IND", AddressingMode.INDIRECT),
29
            Map.entry("IND_X", AddressingMode.INDIRECT_X),
30
            Map.entry("IND_Y", AddressingMode.INDIRECT_Y),
31
            Map.entry("REL", AddressingMode.RELATIVE)
32
    );
33
34
    private static final Map<String, Map<AddressingMode, MOS6502OpCode>> BY_MNEMONIC_AND_MODE = buildTable();
35
    private static final Map<MOS6502OpCode, AddressingMode> MODE_BY_OPCODE = buildReverseTable();
36
37
    private OpCodeTable() {
38
    }
39
40
    private static Map<String, Map<AddressingMode, MOS6502OpCode>> buildTable() {
41
        final Map<String, Map<AddressingMode, MOS6502OpCode>> table = new HashMap<>();
42
43
        for (final MOS6502OpCode opcode : MOS6502OpCode.values()) {
44
            final String[] parts = opcode.name().split("_", 2);
45
            final AddressingMode mode = MODE_BY_SUFFIX.get(parts[1]);
46
47
            table.computeIfAbsent(parts[0], mnemonic -> new EnumMap<>(AddressingMode.class)).put(mode, opcode);
48
        }
49
50
        return table;
51
    }
52
53
    private static Map<MOS6502OpCode, AddressingMode> buildReverseTable() {
54
        final Map<MOS6502OpCode, AddressingMode> table = new EnumMap<>(MOS6502OpCode.class);
55
56
        for (final MOS6502OpCode opcode : MOS6502OpCode.values()) {
57
            final String[] parts = opcode.name().split("_", 2);
58
            table.put(opcode, MODE_BY_SUFFIX.get(parts[1]));
59
        }
60
61
        return table;
62
    }
63
64
    static boolean supports(final String mnemonic, final AddressingMode mode) {
65
        final Map<AddressingMode, MOS6502OpCode> modes = BY_MNEMONIC_AND_MODE.get(mnemonic);
66 3 1. supports : replaced boolean return with true for com/rox/cpu/mos6502/assembler/OpCodeTable::supports → KILLED
2. supports : negated conditional → KILLED
3. supports : negated conditional → KILLED
        return modes != null && modes.containsKey(mode);
67
    }
68
69
    /** @throws IllegalStateException if the mnemonic/mode pair isn't supported - callers must check {@link #supports} first */
70
    static MOS6502OpCode resolve(final String mnemonic, final AddressingMode mode) {
71
        final Map<AddressingMode, MOS6502OpCode> modes = BY_MNEMONIC_AND_MODE.get(mnemonic);
72 2 1. resolve : negated conditional → KILLED
2. resolve : negated conditional → KILLED
        if (modes == null || !modes.containsKey(mode)) {
73
            throw new IllegalStateException(mnemonic + " does not support " + mode + " addressing");
74
        }
75 1 1. resolve : replaced return value with null for com/rox/cpu/mos6502/assembler/OpCodeTable::resolve → KILLED
        return modes.get(mode);
76
    }
77
78
    /** @return the addressing modes {@code mnemonic} supports, or an empty set if it's not a known mnemonic */
79
    static Set<AddressingMode> supportedModes(final String mnemonic) {
80
        final Map<AddressingMode, MOS6502OpCode> modes = BY_MNEMONIC_AND_MODE.get(mnemonic);
81 2 1. supportedModes : replaced return value with Collections.emptySet for com/rox/cpu/mos6502/assembler/OpCodeTable::supportedModes → KILLED
2. supportedModes : negated conditional → KILLED
        return modes == null ? Set.of() : modes.keySet();
82
    }
83
84
    static AddressingMode modeOf(final MOS6502OpCode opcode) {
85 1 1. modeOf : replaced return value with null for com/rox/cpu/mos6502/assembler/OpCodeTable::modeOf → KILLED
        return MODE_BY_OPCODE.get(opcode);
86
    }
87
}

Mutations

66

1.1
Location : supports
Killed by : com.rox.cpu.mos6502.assembler.OpCodeTableTest.[engine:junit-jupiter]/[class:com.rox.cpu.mos6502.assembler.OpCodeTableTest]/[method:supportsIsFalseForACompletelyUnknownMnemonic()]
replaced boolean return with true for com/rox/cpu/mos6502/assembler/OpCodeTable::supports → KILLED

2.2
Location : supports
Killed by : com.rox.cpu.mos6502.assembler.OpCodeTableTest.[engine:junit-jupiter]/[class:com.rox.cpu.mos6502.assembler.OpCodeTableTest]/[method:supportsIsFalseForACompletelyUnknownMnemonic()]
negated conditional → KILLED

3.3
Location : supports
Killed by : com.rox.cpu.mos6502.assembler.OpCodeTableTest.[engine:junit-jupiter]/[class:com.rox.cpu.mos6502.assembler.OpCodeTableTest]/[method:supportsReturnsTrueOnlyForModesTheMnemonicActuallyHas()]
negated conditional → KILLED

72

1.1
Location : resolve
Killed by : com.rox.cpu.mos6502.assembler.OpCodeTableTest.[engine:junit-jupiter]/[class:com.rox.cpu.mos6502.assembler.OpCodeTableTest]/[method:resolveThrowsForACompletelyUnknownMnemonic()]
negated conditional → KILLED

2.2
Location : resolve
Killed by : com.rox.cpu.mos6502.assembler.OpCodeTableTest.[engine:junit-jupiter]/[class:com.rox.cpu.mos6502.assembler.OpCodeTableTest]/[method:resolveThrowsForAnUnsupportedModeCombination()]
negated conditional → KILLED

75

1.1
Location : resolve
Killed by : com.rox.cpu.mos6502.assembler.OpCodeTableTest.[engine:junit-jupiter]/[class:com.rox.cpu.mos6502.assembler.OpCodeTableTest]/[method:resolveFindsTheOpcodeForAKnownMnemonicAndMode()]
replaced return value with null for com/rox/cpu/mos6502/assembler/OpCodeTable::resolve → KILLED

81

1.1
Location : supportedModes
Killed by : com.rox.cpu.mos6502.assembler.OpCodeTableTest.[engine:junit-jupiter]/[class:com.rox.cpu.mos6502.assembler.OpCodeTableTest]/[method:supportedModesListsExactlyWhatTheMnemonicSupports()]
replaced return value with Collections.emptySet for com/rox/cpu/mos6502/assembler/OpCodeTable::supportedModes → KILLED

2.2
Location : supportedModes
Killed by : com.rox.cpu.mos6502.assembler.OpCodeTableTest.[engine:junit-jupiter]/[class:com.rox.cpu.mos6502.assembler.OpCodeTableTest]/[method:supportedModesIsEmptyForAnUnknownMnemonic()]
negated conditional → KILLED

85

1.1
Location : modeOf
Killed by : com.rox.cpu.mos6502.assembler.OpCodeTableTest.[engine:junit-jupiter]/[class:com.rox.cpu.mos6502.assembler.OpCodeTableTest]/[method:modeOfIsTheInverseOfResolveForEveryOfficialOpcode()]
replaced return value with null for com/rox/cpu/mos6502/assembler/OpCodeTable::modeOf → KILLED

Active mutators

Tests examined


Report generated by PIT 1.22.1