mos6502/
instruction.rs

1// Copyright (C) 2014 The 6502-rs Developers
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are met:
7// 1. Redistributions of source code must retain the above copyright
8//    notice, this list of conditions and the following disclaimer.
9// 2. Redistributions in binary form must reproduce the above copyright
10//    notice, this list of conditions and the following disclaimer in the
11//    documentation and/or other materials provided with the distribution.
12// 3. Neither the names of the copyright holders nor the names of any
13//    contributors may be used to endorse or promote products derived from this
14//    software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26// POSSIBILITY OF SUCH DAMAGE.
27
28#[derive(Copy, Clone, Debug, PartialEq, Eq)]
29pub enum Instruction {
30    // ADd with Carry
31    ADC,
32
33    // ADd with Carry. This one has now decimal mode.
34    ADCnd,
35
36    // logical AND (bitwise)
37    AND,
38
39    // Arithmetic Shift Left
40    ASL,
41
42    // Branch if Carry Clear
43    BCC,
44
45    // Branch if Carry Set
46    BCS,
47
48    // Branch if Equal (to zero?)
49    BEQ,
50
51    // BIT test
52    BIT,
53
54    // Branch if Minus
55    BMI,
56
57    // Branch if Not Equal
58    BNE,
59
60    // Branch if Positive
61    BPL,
62
63    // Unconditional BRAnch
64    BRA,
65
66    // BReaK
67    BRK,
68
69    // BReaK, clearing decimal flag
70    BRKcld,
71
72    // Branch if oVerflow Clear
73    BVC,
74
75    // Branch if oVerflow Set
76    BVS,
77
78    // CLear Carry flag
79    CLC,
80
81    // Clear Decimal Mode
82    CLD,
83
84    // Clear Interrupt Disable
85    CLI,
86
87    // Clear oVerflow flag
88    CLV,
89
90    // Compare
91    CMP,
92
93    // Compare X register
94    CPX,
95
96    // Compare Y register
97    CPY,
98
99    // DECrement memory
100    DEC,
101
102    // DEcrement X register
103    DEX,
104
105    // DEcrement Y register
106    DEY,
107
108    // Exclusive OR (bitwise)
109    EOR,
110
111    // INCrement memory
112    INC,
113
114    // INcrement X register
115    INX,
116
117    // INcrement Y register
118    INY,
119
120    // JuMP
121    JMP,
122
123    // Jump to SubRoutine
124    JSR,
125
126    // LoaD Accumulator
127    LDA,
128
129    // LoaD X register
130    LDX,
131
132    // LoaD Y register
133    LDY,
134
135    // Logical Shift Right
136    LSR,
137
138    // No OPeration
139    NOP,
140
141    // inclusive OR (bitwise)
142    ORA,
143
144    // PusH Accumulator
145    PHA,
146
147    // PusH X
148    PHX,
149
150    // PusH Y
151    PHY,
152
153    // PusH Processor status
154    PHP,
155
156    // PuLl Accumulator
157    PLA,
158
159    // PuLl X
160    PLX,
161
162    // PuLl Y
163    PLY,
164
165    // PuLl Processor status
166    PLP,
167
168    // ROtate Left
169    ROL,
170
171    // ROtate Right
172    ROR,
173
174    // ReTurn from Interrupt
175    RTI,
176
177    // ReTurn from Subroutine
178    RTS,
179
180    // SuBtract with Carry
181    SBC,
182
183    // SuBtract with Carry. This one has now decimal mode.
184    SBCnd,
185
186    // SEt Carry flag
187    SEC,
188
189    // SEt Decimal flag
190    SED,
191
192    // SEt Interrupt disable
193    SEI,
194
195    // STore Accumulator
196    STA,
197
198    // STore X register
199    STX,
200
201    // STore Y register
202    STY,
203
204    // STore Zero
205    STZ,
206
207    // Transfer Accumulator to X
208    TAX,
209
210    // Transfer Accumulator to Y
211    TAY,
212
213    // Test and Reset Bits
214    TRB,
215
216    // Test and Set Bits
217    TSB,
218
219    // Transfer Stack pointer to X
220    TSX,
221
222    // Transfer X to Accumulator
223    TXA,
224
225    // Transfer X to Stack pointer
226    TXS,
227
228    // Transfer Y to Accumulator
229    TYA,
230}
231
232#[derive(Copy, Clone, Debug)]
233pub enum OpInput {
234    UseImplied,
235    UseImmediate(u8),
236    UseRelative(u16),
237    UseAddress(u16),
238}
239
240#[derive(Copy, Clone, Debug)]
241pub enum AddressingMode {
242    // work directly on accumulator, e. g. `lsr a`.
243    Accumulator,
244
245    // BRK
246    Implied,
247
248    // 8-bit constant in instruction, e. g. `lda #10`.
249    Immediate,
250
251    // zero-page address, e. g. `lda $00`.
252    ZeroPage,
253
254    // address is X register + 8-bit constant, e. g. `lda $80,x`.
255    ZeroPageX,
256
257    // address is Y register + 8-bit constant, e. g. `ldx $10,y`.
258    ZeroPageY,
259
260    // branch target as signed relative offset, e. g. `bne label`.
261    Relative,
262
263    // full 16-bit address, e. g. `jmp $1000`.
264    Absolute,
265
266    // full 16-bit address plus X register, e. g. `sta $1000,X`.
267    AbsoluteX,
268
269    // full 16-bit address plus Y register, e. g. `sta $1000,Y`.
270    AbsoluteY,
271
272    // jump to address stored at address, with the page-crossing bug found in NMOS chips, e. g. `jmp ($1000)`.
273    BuggyIndirect,
274
275    // jump to address stored at address, e. g. `jmp ($1000)`.
276    Indirect,
277
278    // load from address stored at (constant zero page address plus X register), e. g. `lda ($10,X)`.
279    IndexedIndirectX,
280
281    // load from (address stored at constant zero page address) plus Y register, e. g. `lda ($10),Y`.
282    IndirectIndexedY,
283
284    // Address stored at constant zero page address
285    ZeroPageIndirect,
286}
287
288impl AddressingMode {
289    #[must_use]
290    pub const fn extra_bytes(self) -> u16 {
291        match self {
292            AddressingMode::Accumulator => 0,
293            AddressingMode::Implied => 0,
294            AddressingMode::Immediate => 1,
295            AddressingMode::ZeroPage => 1,
296            AddressingMode::ZeroPageX => 1,
297            AddressingMode::ZeroPageY => 1,
298            AddressingMode::Relative => 1,
299            AddressingMode::Absolute => 2,
300            AddressingMode::AbsoluteX => 2,
301            AddressingMode::AbsoluteY => 2,
302            AddressingMode::Indirect => 2,
303            AddressingMode::BuggyIndirect => 2,
304            AddressingMode::IndexedIndirectX => 1,
305            AddressingMode::IndirectIndexedY => 1,
306            AddressingMode::ZeroPageIndirect => 1,
307        }
308    }
309}
310
311pub type DecodedInstr = (Instruction, OpInput);
312
313/// The NMOS 6502 variant. This one is present in the Commodore 64, early Apple IIs, etc.
314#[derive(Copy, Clone, Debug, Default)]
315pub struct Nmos6502;
316
317impl crate::Variant for Nmos6502 {
318    fn decode(opcode: u8) -> Option<(Instruction, AddressingMode)> {
319        match opcode {
320            0x00 => Some((Instruction::BRK, AddressingMode::Implied)),
321            0x01 => Some((Instruction::ORA, AddressingMode::IndexedIndirectX)),
322            0x02 => None,
323            0x03 => None,
324            0x04 => None,
325            0x05 => Some((Instruction::ORA, AddressingMode::ZeroPage)),
326            0x06 => Some((Instruction::ASL, AddressingMode::ZeroPage)),
327            0x07 => None,
328            0x08 => Some((Instruction::PHP, AddressingMode::Implied)),
329            0x09 => Some((Instruction::ORA, AddressingMode::Immediate)),
330            0x0a => Some((Instruction::ASL, AddressingMode::Accumulator)),
331            0x0b => None,
332            0x0c => None,
333            0x0d => Some((Instruction::ORA, AddressingMode::Absolute)),
334            0x0e => Some((Instruction::ASL, AddressingMode::Absolute)),
335            0x0f => None,
336            0x10 => Some((Instruction::BPL, AddressingMode::Relative)),
337            0x11 => Some((Instruction::ORA, AddressingMode::IndirectIndexedY)),
338            0x12 => None,
339            0x13 => None,
340            0x14 => None,
341            0x15 => Some((Instruction::ORA, AddressingMode::ZeroPageX)),
342            0x16 => Some((Instruction::ASL, AddressingMode::ZeroPageX)),
343            0x17 => None,
344            0x18 => Some((Instruction::CLC, AddressingMode::Implied)),
345            0x19 => Some((Instruction::ORA, AddressingMode::AbsoluteY)),
346            0x1a => None,
347            0x1b => None,
348            0x1c => None,
349            0x1d => Some((Instruction::ORA, AddressingMode::AbsoluteX)),
350            0x1e => Some((Instruction::ASL, AddressingMode::AbsoluteX)),
351            0x1f => None,
352            0x20 => Some((Instruction::JSR, AddressingMode::Absolute)),
353            0x21 => Some((Instruction::AND, AddressingMode::IndexedIndirectX)),
354            0x22 => None,
355            0x23 => None,
356            0x24 => Some((Instruction::BIT, AddressingMode::ZeroPage)),
357            0x25 => Some((Instruction::AND, AddressingMode::ZeroPage)),
358            0x26 => Some((Instruction::ROL, AddressingMode::ZeroPage)),
359            0x27 => None,
360            0x28 => Some((Instruction::PLP, AddressingMode::Implied)),
361            0x29 => Some((Instruction::AND, AddressingMode::Immediate)),
362            0x2a => Some((Instruction::ROL, AddressingMode::Accumulator)),
363            0x2b => None,
364            0x2c => Some((Instruction::BIT, AddressingMode::Absolute)),
365            0x2d => Some((Instruction::AND, AddressingMode::Absolute)),
366            0x2e => Some((Instruction::ROL, AddressingMode::Absolute)),
367            0x2f => None,
368            0x30 => Some((Instruction::BMI, AddressingMode::Relative)),
369            0x31 => Some((Instruction::AND, AddressingMode::IndirectIndexedY)),
370            0x32 => None,
371            0x33 => None,
372            0x34 => None,
373            0x35 => Some((Instruction::AND, AddressingMode::ZeroPageX)),
374            0x36 => Some((Instruction::ROL, AddressingMode::ZeroPageX)),
375            0x37 => None,
376            0x38 => Some((Instruction::SEC, AddressingMode::Implied)),
377            0x39 => Some((Instruction::AND, AddressingMode::AbsoluteY)),
378            0x3a => None,
379            0x3b => None,
380            0x3c => None,
381            0x3d => Some((Instruction::AND, AddressingMode::AbsoluteX)),
382            0x3e => Some((Instruction::ROL, AddressingMode::AbsoluteX)),
383            0x3f => None,
384            0x40 => Some((Instruction::RTI, AddressingMode::Implied)),
385            0x41 => Some((Instruction::EOR, AddressingMode::IndexedIndirectX)),
386            0x42 => None,
387            0x43 => None,
388            0x44 => None,
389            0x45 => Some((Instruction::EOR, AddressingMode::ZeroPage)),
390            0x46 => Some((Instruction::LSR, AddressingMode::ZeroPage)),
391            0x47 => None,
392            0x48 => Some((Instruction::PHA, AddressingMode::Implied)),
393            0x49 => Some((Instruction::EOR, AddressingMode::Immediate)),
394            0x4a => Some((Instruction::LSR, AddressingMode::Accumulator)),
395            0x4b => None,
396            0x4c => Some((Instruction::JMP, AddressingMode::Absolute)),
397            0x4d => Some((Instruction::EOR, AddressingMode::Absolute)),
398            0x4e => Some((Instruction::LSR, AddressingMode::Absolute)),
399            0x4f => None,
400            0x50 => Some((Instruction::BVC, AddressingMode::Relative)),
401            0x51 => Some((Instruction::EOR, AddressingMode::IndirectIndexedY)),
402            0x52 => None,
403            0x53 => None,
404            0x54 => None,
405            0x55 => Some((Instruction::EOR, AddressingMode::ZeroPageX)),
406            0x56 => Some((Instruction::LSR, AddressingMode::ZeroPageX)),
407            0x57 => None,
408            0x58 => Some((Instruction::CLI, AddressingMode::Implied)),
409            0x59 => Some((Instruction::EOR, AddressingMode::AbsoluteY)),
410            0x5a => None,
411            0x5b => None,
412            0x5c => None,
413            0x5d => Some((Instruction::EOR, AddressingMode::AbsoluteX)),
414            0x5e => Some((Instruction::LSR, AddressingMode::AbsoluteX)),
415            0x5f => None,
416            0x60 => Some((Instruction::RTS, AddressingMode::Implied)),
417            0x61 => Some((Instruction::ADC, AddressingMode::IndexedIndirectX)),
418            0x62 => None,
419            0x63 => None,
420            0x64 => None,
421            0x65 => Some((Instruction::ADC, AddressingMode::ZeroPage)),
422            0x66 => Some((Instruction::ROR, AddressingMode::ZeroPage)),
423            0x67 => None,
424            0x68 => Some((Instruction::PLA, AddressingMode::Implied)),
425            0x69 => Some((Instruction::ADC, AddressingMode::Immediate)),
426            0x6a => Some((Instruction::ROR, AddressingMode::Accumulator)),
427            0x6b => None,
428            0x6c => Some((Instruction::JMP, AddressingMode::BuggyIndirect)),
429            0x6d => Some((Instruction::ADC, AddressingMode::Absolute)),
430            0x6e => Some((Instruction::ROR, AddressingMode::Absolute)),
431            0x6f => None,
432            0x70 => Some((Instruction::BVS, AddressingMode::Relative)),
433            0x71 => Some((Instruction::ADC, AddressingMode::IndirectIndexedY)),
434            0x72 => None,
435            0x73 => None,
436            0x74 => None,
437            0x75 => Some((Instruction::ADC, AddressingMode::ZeroPageX)),
438            0x76 => Some((Instruction::ROR, AddressingMode::ZeroPageX)),
439            0x77 => None,
440            0x78 => Some((Instruction::SEI, AddressingMode::Implied)),
441            0x79 => Some((Instruction::ADC, AddressingMode::AbsoluteY)),
442            0x7a => None,
443            0x7b => None,
444            0x7c => None,
445            0x7d => Some((Instruction::ADC, AddressingMode::AbsoluteX)),
446            0x7e => Some((Instruction::ROR, AddressingMode::AbsoluteX)),
447            0x7f => None,
448            0x80 => None,
449            0x81 => Some((Instruction::STA, AddressingMode::IndexedIndirectX)),
450            0x82 => None,
451            0x83 => None,
452            0x84 => Some((Instruction::STY, AddressingMode::ZeroPage)),
453            0x85 => Some((Instruction::STA, AddressingMode::ZeroPage)),
454            0x86 => Some((Instruction::STX, AddressingMode::ZeroPage)),
455            0x87 => None,
456            0x88 => Some((Instruction::DEY, AddressingMode::Implied)),
457            0x89 => None,
458            0x8a => Some((Instruction::TXA, AddressingMode::Implied)),
459            0x8b => None,
460            0x8c => Some((Instruction::STY, AddressingMode::Absolute)),
461            0x8d => Some((Instruction::STA, AddressingMode::Absolute)),
462            0x8e => Some((Instruction::STX, AddressingMode::Absolute)),
463            0x8f => None,
464            0x90 => Some((Instruction::BCC, AddressingMode::Relative)),
465            0x91 => Some((Instruction::STA, AddressingMode::IndirectIndexedY)),
466            0x92 => None,
467            0x93 => None,
468            0x94 => Some((Instruction::STY, AddressingMode::ZeroPageX)),
469            0x95 => Some((Instruction::STA, AddressingMode::ZeroPageX)),
470            0x96 => Some((Instruction::STX, AddressingMode::ZeroPageY)),
471            0x97 => None,
472            0x98 => Some((Instruction::TYA, AddressingMode::Implied)),
473            0x99 => Some((Instruction::STA, AddressingMode::AbsoluteY)),
474            0x9a => Some((Instruction::TXS, AddressingMode::Implied)),
475            0x9b => None,
476            0x9c => None,
477            0x9d => Some((Instruction::STA, AddressingMode::AbsoluteX)),
478            0x9e => None,
479            0x9f => None,
480            0xa0 => Some((Instruction::LDY, AddressingMode::Immediate)),
481            0xa1 => Some((Instruction::LDA, AddressingMode::IndexedIndirectX)),
482            0xa2 => Some((Instruction::LDX, AddressingMode::Immediate)),
483            0xa3 => None,
484            0xa4 => Some((Instruction::LDY, AddressingMode::ZeroPage)),
485            0xa5 => Some((Instruction::LDA, AddressingMode::ZeroPage)),
486            0xa6 => Some((Instruction::LDX, AddressingMode::ZeroPage)),
487            0xa7 => None,
488            0xa8 => Some((Instruction::TAY, AddressingMode::Implied)),
489            0xa9 => Some((Instruction::LDA, AddressingMode::Immediate)),
490            0xaa => Some((Instruction::TAX, AddressingMode::Implied)),
491            0xab => None,
492            0xac => Some((Instruction::LDY, AddressingMode::Absolute)),
493            0xad => Some((Instruction::LDA, AddressingMode::Absolute)),
494            0xae => Some((Instruction::LDX, AddressingMode::Absolute)),
495            0xaf => None,
496            0xb0 => Some((Instruction::BCS, AddressingMode::Relative)),
497            0xb1 => Some((Instruction::LDA, AddressingMode::IndirectIndexedY)),
498            0xb2 => None,
499            0xb3 => None,
500            0xb4 => Some((Instruction::LDY, AddressingMode::ZeroPageX)),
501            0xb5 => Some((Instruction::LDA, AddressingMode::ZeroPageX)),
502            0xb6 => Some((Instruction::LDX, AddressingMode::ZeroPageY)),
503            0xb7 => None,
504            0xb8 => Some((Instruction::CLV, AddressingMode::Implied)),
505            0xb9 => Some((Instruction::LDA, AddressingMode::AbsoluteY)),
506            0xba => Some((Instruction::TSX, AddressingMode::Implied)),
507            0xbb => None,
508            0xbc => Some((Instruction::LDY, AddressingMode::AbsoluteX)),
509            0xbd => Some((Instruction::LDA, AddressingMode::AbsoluteX)),
510            0xbe => Some((Instruction::LDX, AddressingMode::AbsoluteY)),
511            0xbf => None,
512            0xc0 => Some((Instruction::CPY, AddressingMode::Immediate)),
513            0xc1 => Some((Instruction::CMP, AddressingMode::IndexedIndirectX)),
514            0xc2 => None,
515            0xc3 => None,
516            0xc4 => Some((Instruction::CPY, AddressingMode::ZeroPage)),
517            0xc5 => Some((Instruction::CMP, AddressingMode::ZeroPage)),
518            0xc6 => Some((Instruction::DEC, AddressingMode::ZeroPage)),
519            0xc7 => None,
520            0xc8 => Some((Instruction::INY, AddressingMode::Implied)),
521            0xc9 => Some((Instruction::CMP, AddressingMode::Immediate)),
522            0xca => Some((Instruction::DEX, AddressingMode::Implied)),
523            0xcb => None,
524            0xcc => Some((Instruction::CPY, AddressingMode::Absolute)),
525            0xcd => Some((Instruction::CMP, AddressingMode::Absolute)),
526            0xce => Some((Instruction::DEC, AddressingMode::Absolute)),
527            0xcf => None,
528            0xd0 => Some((Instruction::BNE, AddressingMode::Relative)),
529            0xd1 => Some((Instruction::CMP, AddressingMode::IndirectIndexedY)),
530            0xd2 => None,
531            0xd3 => None,
532            0xd4 => None,
533            0xd5 => Some((Instruction::CMP, AddressingMode::ZeroPageX)),
534            0xd6 => Some((Instruction::DEC, AddressingMode::ZeroPageX)),
535            0xd7 => None,
536            0xd8 => Some((Instruction::CLD, AddressingMode::Implied)),
537            0xd9 => Some((Instruction::CMP, AddressingMode::AbsoluteY)),
538            0xda => None,
539            0xdb => None,
540            0xdc => None,
541            0xdd => Some((Instruction::CMP, AddressingMode::AbsoluteX)),
542            0xde => Some((Instruction::DEC, AddressingMode::AbsoluteX)),
543            0xdf => None,
544            0xe0 => Some((Instruction::CPX, AddressingMode::Immediate)),
545            0xe1 => Some((Instruction::SBC, AddressingMode::IndexedIndirectX)),
546            0xe2 => None,
547            0xe3 => None,
548            0xe4 => Some((Instruction::CPX, AddressingMode::ZeroPage)),
549            0xe5 => Some((Instruction::SBC, AddressingMode::ZeroPage)),
550            0xe6 => Some((Instruction::INC, AddressingMode::ZeroPage)),
551            0xe7 => None,
552            0xe8 => Some((Instruction::INX, AddressingMode::Implied)),
553            0xe9 => Some((Instruction::SBC, AddressingMode::Immediate)),
554            0xea => Some((Instruction::NOP, AddressingMode::Implied)),
555            0xeb => None,
556            0xec => Some((Instruction::CPX, AddressingMode::Absolute)),
557            0xed => Some((Instruction::SBC, AddressingMode::Absolute)),
558            0xee => Some((Instruction::INC, AddressingMode::Absolute)),
559            0xef => None,
560            0xf0 => Some((Instruction::BEQ, AddressingMode::Relative)),
561            0xf1 => Some((Instruction::SBC, AddressingMode::IndirectIndexedY)),
562            0xf2 => None,
563            0xf3 => None,
564            0xf4 => None,
565            0xf5 => Some((Instruction::SBC, AddressingMode::ZeroPageX)),
566            0xf6 => Some((Instruction::INC, AddressingMode::ZeroPageX)),
567            0xf7 => None,
568            0xf8 => Some((Instruction::SED, AddressingMode::Implied)),
569            0xf9 => Some((Instruction::SBC, AddressingMode::AbsoluteY)),
570            0xfa => None,
571            0xfb => None,
572            0xfc => None,
573            0xfd => Some((Instruction::SBC, AddressingMode::AbsoluteX)),
574            0xfe => Some((Instruction::INC, AddressingMode::AbsoluteX)),
575            0xff => None,
576        }
577    }
578}
579
580/// The Ricoh variant which has no decimal mode. This is what to use if you want
581/// to emulate the NES.
582#[derive(Copy, Clone, Debug, Default)]
583pub struct Ricoh2a03;
584
585impl crate::Variant for Ricoh2a03 {
586    fn decode(opcode: u8) -> Option<(Instruction, AddressingMode)> {
587        // It's the same as on NMOS, but doesn't support decimal mode.
588        match Nmos6502::decode(opcode) {
589            Some((Instruction::ADC, addressing_mode)) => {
590                Some((Instruction::ADCnd, addressing_mode))
591            }
592            Some((Instruction::SBC, addressing_mode)) => {
593                Some((Instruction::SBCnd, addressing_mode))
594            }
595            something_else => something_else,
596        }
597    }
598}
599
600/// Emulates some very early 6502s which have no ROR instruction. This one is used in very early
601/// KIM-1s.
602#[derive(Copy, Clone, Debug, Default)]
603pub struct RevisionA;
604
605impl crate::Variant for RevisionA {
606    fn decode(opcode: u8) -> Option<(Instruction, AddressingMode)> {
607        // It's the same as on NMOS, but has no ROR instruction.
608        match Nmos6502::decode(opcode) {
609            Some((Instruction::ROR, _)) => None,
610            something_else => something_else,
611        }
612    }
613}
614
615/// Emulates the 65C02, which has a few bugfixes, and another addressing mode
616#[derive(Copy, Clone, Debug, Default)]
617pub struct Cmos6502;
618
619impl crate::Variant for Cmos6502 {
620    fn decode(opcode: u8) -> Option<(Instruction, AddressingMode)> {
621        // TODO: We obviously need to add the other CMOS instructions here.
622        match opcode {
623            0x00 => Some((Instruction::BRKcld, AddressingMode::Implied)),
624            0x1a => Some((Instruction::INC, AddressingMode::Accumulator)),
625            0x3a => Some((Instruction::DEC, AddressingMode::Accumulator)),
626            0x6c => Some((Instruction::JMP, AddressingMode::Indirect)),
627            0x80 => Some((Instruction::BRA, AddressingMode::Relative)),
628            0x64 => Some((Instruction::STZ, AddressingMode::ZeroPage)),
629            0x74 => Some((Instruction::STZ, AddressingMode::ZeroPageX)),
630            0x9c => Some((Instruction::STZ, AddressingMode::Absolute)),
631            0x9e => Some((Instruction::STZ, AddressingMode::AbsoluteX)),
632            0x7a => Some((Instruction::PLY, AddressingMode::Implied)),
633            0xfa => Some((Instruction::PLX, AddressingMode::Implied)),
634            0x5a => Some((Instruction::PHY, AddressingMode::Implied)),
635            0xda => Some((Instruction::PHX, AddressingMode::Implied)),
636            0x04 => Some((Instruction::TSB, AddressingMode::ZeroPage)),
637            0x14 => Some((Instruction::TRB, AddressingMode::ZeroPage)),
638            0x0c => Some((Instruction::TSB, AddressingMode::Absolute)),
639            0x1c => Some((Instruction::TRB, AddressingMode::Absolute)),
640            0x12 => Some((Instruction::ORA, AddressingMode::ZeroPageIndirect)),
641            0x32 => Some((Instruction::AND, AddressingMode::ZeroPageIndirect)),
642            0x52 => Some((Instruction::EOR, AddressingMode::ZeroPageIndirect)),
643            0x72 => Some((Instruction::ADC, AddressingMode::ZeroPageIndirect)),
644            0x92 => Some((Instruction::STA, AddressingMode::ZeroPageIndirect)),
645            0xb2 => Some((Instruction::LDA, AddressingMode::ZeroPageIndirect)),
646            0xd2 => Some((Instruction::CMP, AddressingMode::ZeroPageIndirect)),
647            0xf2 => Some((Instruction::SBC, AddressingMode::ZeroPageIndirect)),
648            0x89 => Some((Instruction::BIT, AddressingMode::Immediate)),
649            _ => Nmos6502::decode(opcode),
650        }
651    }
652}