1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
use crate::machine::{Cpu, MemoryReadOnly};
use crate::{Address, UnknownOpcode};
use std::fmt;

#[derive(Debug, Clone, Copy)]
pub enum InstructionType {
    Adc,
    Ahx,
    Alr,
    Arr,
    Anc,
    And,
    Asl,
    Axs,
    Bcc,
    Bcs,
    Beq,
    Bmi,
    Bne,
    Bpl,
    Brk,
    Bvc,
    Bvs,
    Bit,
    Clc,
    Cld,
    Cli,
    Clv,
    Cmp,
    Cpx,
    Cpy,
    Dcp,
    Dec,
    Dex,
    Dey,
    Eor,
    Ign,
    Inc,
    Inx,
    Iny,
    Isc,
    Jmp,
    Jsr,
    Lax,
    Lda,
    Ldx,
    Ldy,
    Lsr,
    Nop,
    Ora,
    Pha,
    Php,
    Pla,
    Plp,
    Rla,
    Rol,
    Ror,
    Rra,
    Rti,
    Rts,
    Sax,
    Sbc,
    Sec,
    Sed,
    Sei,
    Skb,
    Slo,
    Sre,
    Sta,
    Stx,
    Sty,
    Sxa,
    Sya,
    Tax,
    Tay,
    Tsx,
    Txa,
    Txs,
    Tya,
}
#[derive(Debug, Clone, Copy)]
pub enum AddressingMode {
    Absolute,
    AbsoluteXIndexed,
    AbsoluteYIndexed,
    Accumulator,
    Implied,
    Immediate,
    Indirect,
    IndirectYIndexed,
    Relative,
    XIndexedIndirect,
    ZeroPage,
    ZeroPageXIndexed,
    ZeroPageYIndexed,
}
impl AddressingMode {
    fn operand_bytes(self) -> usize {
        use AddressingMode::*;
        match self {
            Absolute => 2,
            AbsoluteXIndexed => 2,
            AbsoluteYIndexed => 2,
            Implied => 0,
            Accumulator => 0,
            Immediate => 1,
            Indirect => 2,
            IndirectYIndexed => 1,
            Relative => 1,
            XIndexedIndirect => 1,
            ZeroPage => 1,
            ZeroPageXIndexed => 1,
            ZeroPageYIndexed => 1,
        }
    }
}
#[derive(Debug, Clone, Copy)]
pub struct Instruction {
    instruction_type: InstructionType,
    addressing_mode: AddressingMode,
}

impl Instruction {
    fn new(instruction_type: InstructionType, addressing_mode: AddressingMode) -> Self {
        Self {
            instruction_type,
            addressing_mode,
        }
    }
    pub fn size(&self) -> usize {
        self.addressing_mode.operand_bytes() + 1
    }
    pub fn from_opcode(opcode: u8) -> Result<Self, UnknownOpcode> {
        use crate::opcode;
        use AddressingMode::*;
        use InstructionType::*;
        let (instruction_type, addressing_mode) = match opcode {
            opcode::adc::ABSOLUTE => (Adc, Absolute),
            opcode::adc::ABSOLUTE_X_INDEXED => (Adc, AbsoluteXIndexed),
            opcode::adc::ABSOLUTE_Y_INDEXED => (Adc, AbsoluteYIndexed),
            opcode::adc::IMMEDIATE => (Adc, Immediate),
            opcode::adc::INDIRECT_Y_INDEXED => (Adc, IndirectYIndexed),
            opcode::adc::X_INDEXED_INDIRECT => (Adc, XIndexedIndirect),
            opcode::adc::ZERO_PAGE => (Adc, ZeroPage),
            opcode::adc::ZERO_PAGE_X_INDEXED => (Adc, ZeroPageXIndexed),
            opcode::ahx::unofficial0::ABSOLUTE_Y_INDEXED => (Ahx, AbsoluteYIndexed),
            opcode::ahx::unofficial0::INDIRECT_Y_INDEXED => (Ahx, IndirectYIndexed),
            opcode::alr::unofficial0::IMMEDIATE => (Alr, Immediate),
            opcode::arr::unofficial0::IMMEDIATE => (Arr, Immediate),
            opcode::anc::unofficial0::IMMEDIATE => (Anc, Immediate),
            opcode::anc::unofficial1::IMMEDIATE => (Anc, Immediate),
            opcode::and::ABSOLUTE => (And, Absolute),
            opcode::and::ABSOLUTE_X_INDEXED => (And, AbsoluteXIndexed),
            opcode::and::ABSOLUTE_Y_INDEXED => (And, AbsoluteYIndexed),
            opcode::and::IMMEDIATE => (And, Immediate),
            opcode::and::INDIRECT_Y_INDEXED => (And, IndirectYIndexed),
            opcode::and::X_INDEXED_INDIRECT => (And, XIndexedIndirect),
            opcode::and::ZERO_PAGE => (And, ZeroPage),
            opcode::and::ZERO_PAGE_X_INDEXED => (And, ZeroPageXIndexed),
            opcode::asl::ABSOLUTE => (Asl, Absolute),
            opcode::asl::ABSOLUTE_X_INDEXED => (Asl, AbsoluteXIndexed),
            opcode::asl::ACCUMULATOR => (Asl, Accumulator),
            opcode::asl::ZERO_PAGE => (Asl, ZeroPage),
            opcode::asl::ZERO_PAGE_X_INDEXED => (Asl, ZeroPageXIndexed),
            opcode::axs::unofficial0::IMMEDIATE => (Axs, Immediate),
            opcode::bcc::RELATIVE => (Bcc, Relative),
            opcode::bcs::RELATIVE => (Bcs, Relative),
            opcode::beq::RELATIVE => (Beq, Relative),
            opcode::bmi::RELATIVE => (Bmi, Relative),
            opcode::bne::RELATIVE => (Bne, Relative),
            opcode::bpl::RELATIVE => (Bpl, Relative),
            opcode::brk::IMPLIED => (Brk, Implied),
            opcode::bvc::RELATIVE => (Bvc, Relative),
            opcode::bvs::RELATIVE => (Bvs, Relative),
            opcode::bit::ABSOLUTE => (Bit, Absolute),
            opcode::bit::ZERO_PAGE => (Bit, ZeroPage),
            opcode::clc::IMPLIED => (Clc, Implied),
            opcode::cld::IMPLIED => (Cld, Implied),
            opcode::cli::IMPLIED => (Cli, Implied),
            opcode::clv::IMPLIED => (Clv, Implied),
            opcode::cmp::ABSOLUTE => (Cmp, Absolute),
            opcode::cmp::ABSOLUTE_X_INDEXED => (Cmp, AbsoluteXIndexed),
            opcode::cmp::ABSOLUTE_Y_INDEXED => (Cmp, AbsoluteYIndexed),
            opcode::cmp::IMMEDIATE => (Cmp, Immediate),
            opcode::cmp::INDIRECT_Y_INDEXED => (Cmp, IndirectYIndexed),
            opcode::cmp::X_INDEXED_INDIRECT => (Cmp, XIndexedIndirect),
            opcode::cmp::ZERO_PAGE => (Cmp, ZeroPage),
            opcode::cmp::ZERO_PAGE_X_INDEXED => (Cmp, ZeroPageXIndexed),
            opcode::cpx::ABSOLUTE => (Cpx, Absolute),
            opcode::cpx::IMMEDIATE => (Cpx, Immediate),
            opcode::cpx::ZERO_PAGE => (Cpx, ZeroPage),
            opcode::cpy::ABSOLUTE => (Cpy, Absolute),
            opcode::cpy::IMMEDIATE => (Cpy, Immediate),
            opcode::cpy::ZERO_PAGE => (Cpy, ZeroPage),
            opcode::dcp::unofficial0::X_INDEXED_INDIRECT => (Dcp, XIndexedIndirect),
            opcode::dcp::unofficial0::ZERO_PAGE => (Dcp, ZeroPage),
            opcode::dcp::unofficial0::ABSOLUTE => (Dcp, Absolute),
            opcode::dcp::unofficial0::INDIRECT_Y_INDEXED => (Dcp, IndirectYIndexed),
            opcode::dcp::unofficial0::ZERO_PAGE_X_INDEXED => (Dcp, ZeroPageXIndexed),
            opcode::dcp::unofficial0::ABSOLUTE_X_INDEXED => (Dcp, AbsoluteXIndexed),
            opcode::dcp::unofficial0::ABSOLUTE_Y_INDEXED => (Dcp, AbsoluteYIndexed),
            opcode::dec::ABSOLUTE => (Dec, Absolute),
            opcode::dec::ABSOLUTE_X_INDEXED => (Dec, AbsoluteXIndexed),
            opcode::dec::ZERO_PAGE => (Dec, ZeroPage),
            opcode::dec::ZERO_PAGE_X_INDEXED => (Dec, ZeroPageXIndexed),
            opcode::dex::IMPLIED => (Dex, Implied),
            opcode::dey::IMPLIED => (Dey, Implied),
            opcode::eor::ABSOLUTE => (Eor, Absolute),
            opcode::eor::ABSOLUTE_X_INDEXED => (Eor, AbsoluteXIndexed),
            opcode::eor::ABSOLUTE_Y_INDEXED => (Eor, AbsoluteYIndexed),
            opcode::eor::IMMEDIATE => (Eor, Immediate),
            opcode::eor::INDIRECT_Y_INDEXED => (Eor, IndirectYIndexed),
            opcode::eor::X_INDEXED_INDIRECT => (Eor, XIndexedIndirect),
            opcode::eor::ZERO_PAGE => (Eor, ZeroPage),
            opcode::eor::ZERO_PAGE_X_INDEXED => (Eor, ZeroPageXIndexed),
            opcode::ign::unofficial0::ABSOLUTE => (Ign, Absolute),
            opcode::ign::unofficial0::ABSOLUTE_X_INDEXED => (Ign, AbsoluteXIndexed),
            opcode::ign::unofficial0::ZERO_PAGE => (Ign, ZeroPage),
            opcode::ign::unofficial0::ZERO_PAGE_X_INDEXED => (Ign, ZeroPageXIndexed),
            opcode::ign::unofficial1::ABSOLUTE_X_INDEXED => (Ign, AbsoluteXIndexed),
            opcode::ign::unofficial1::ZERO_PAGE => (Ign, ZeroPage),
            opcode::ign::unofficial1::ZERO_PAGE_X_INDEXED => (Ign, ZeroPageXIndexed),
            opcode::ign::unofficial2::ABSOLUTE_X_INDEXED => (Ign, AbsoluteXIndexed),
            opcode::ign::unofficial2::ZERO_PAGE => (Ign, ZeroPage),
            opcode::ign::unofficial2::ZERO_PAGE_X_INDEXED => (Ign, ZeroPageXIndexed),
            opcode::ign::unofficial3::ABSOLUTE_X_INDEXED => (Ign, AbsoluteXIndexed),
            opcode::ign::unofficial3::ZERO_PAGE_X_INDEXED => (Ign, ZeroPageXIndexed),
            opcode::ign::unofficial4::ABSOLUTE_X_INDEXED => (Ign, AbsoluteXIndexed),
            opcode::ign::unofficial4::ZERO_PAGE_X_INDEXED => (Ign, ZeroPageXIndexed),
            opcode::ign::unofficial5::ABSOLUTE_X_INDEXED => (Ign, AbsoluteXIndexed),
            opcode::ign::unofficial5::ZERO_PAGE_X_INDEXED => (Ign, ZeroPageXIndexed),
            opcode::inc::ABSOLUTE => (Inc, Absolute),
            opcode::inc::ABSOLUTE_X_INDEXED => (Inc, AbsoluteXIndexed),
            opcode::inc::ZERO_PAGE => (Inc, ZeroPage),
            opcode::inc::ZERO_PAGE_X_INDEXED => (Inc, ZeroPageXIndexed),
            opcode::inx::IMPLIED => (Inx, Implied),
            opcode::iny::IMPLIED => (Iny, Implied),
            opcode::isc::unofficial0::X_INDEXED_INDIRECT => (Isc, XIndexedIndirect),
            opcode::isc::unofficial0::ZERO_PAGE => (Isc, ZeroPage),
            opcode::isc::unofficial0::ABSOLUTE => (Isc, Absolute),
            opcode::isc::unofficial0::INDIRECT_Y_INDEXED => (Isc, IndirectYIndexed),
            opcode::isc::unofficial0::ZERO_PAGE_X_INDEXED => (Isc, ZeroPageXIndexed),
            opcode::isc::unofficial0::ABSOLUTE_X_INDEXED => (Isc, AbsoluteXIndexed),
            opcode::isc::unofficial0::ABSOLUTE_Y_INDEXED => (Isc, AbsoluteYIndexed),
            opcode::jmp::ABSOLUTE => (Jmp, Absolute),
            opcode::jmp::INDIRECT => (Jmp, Indirect),
            opcode::jsr::ABSOLUTE => (Jsr, Absolute),
            opcode::lax::unofficial0::ABSOLUTE => (Lax, Absolute),
            opcode::lax::unofficial0::ABSOLUTE_Y_INDEXED => (Lax, AbsoluteYIndexed),
            opcode::lax::unofficial0::IMMEDIATE => (Lax, Immediate),
            opcode::lax::unofficial0::X_INDEXED_INDIRECT => (Lax, XIndexedIndirect),
            opcode::lax::unofficial0::INDIRECT_Y_INDEXED => (Lax, IndirectYIndexed),
            opcode::lax::unofficial0::ZERO_PAGE => (Lax, ZeroPage),
            opcode::lax::unofficial0::ZERO_PAGE_Y_INDEXED => (Lax, ZeroPageYIndexed),
            opcode::lda::ABSOLUTE => (Lda, Absolute),
            opcode::lda::ABSOLUTE_X_INDEXED => (Lda, AbsoluteXIndexed),
            opcode::lda::ABSOLUTE_Y_INDEXED => (Lda, AbsoluteYIndexed),
            opcode::lda::IMMEDIATE => (Lda, Immediate),
            opcode::lda::INDIRECT_Y_INDEXED => (Lda, IndirectYIndexed),
            opcode::lda::X_INDEXED_INDIRECT => (Lda, XIndexedIndirect),
            opcode::lda::ZERO_PAGE => (Lda, ZeroPage),
            opcode::lda::ZERO_PAGE_X_INDEXED => (Lda, ZeroPageXIndexed),
            opcode::ldx::ABSOLUTE => (Ldx, Absolute),
            opcode::ldx::ABSOLUTE_Y_INDEXED => (Ldx, AbsoluteYIndexed),
            opcode::ldx::IMMEDIATE => (Ldx, Immediate),
            opcode::ldx::ZERO_PAGE => (Ldx, ZeroPage),
            opcode::ldx::ZERO_PAGE_Y_INDEXED => (Ldx, ZeroPageYIndexed),
            opcode::ldy::ABSOLUTE => (Ldy, Absolute),
            opcode::ldy::ABSOLUTE_X_INDEXED => (Ldy, AbsoluteXIndexed),
            opcode::ldy::IMMEDIATE => (Ldy, Immediate),
            opcode::ldy::ZERO_PAGE => (Ldy, ZeroPage),
            opcode::ldy::ZERO_PAGE_X_INDEXED => (Ldy, ZeroPageXIndexed),
            opcode::lsr::ABSOLUTE => (Lsr, Absolute),
            opcode::lsr::ABSOLUTE_X_INDEXED => (Lsr, AbsoluteXIndexed),
            opcode::lsr::ACCUMULATOR => (Lsr, Accumulator),
            opcode::lsr::ZERO_PAGE => (Lsr, ZeroPage),
            opcode::lsr::ZERO_PAGE_X_INDEXED => (Lsr, ZeroPageXIndexed),
            opcode::nop::IMPLIED => (Nop, Implied),
            opcode::nop::unofficial0::IMPLIED => (Nop, Implied),
            opcode::nop::unofficial1::IMPLIED => (Nop, Implied),
            opcode::nop::unofficial2::IMPLIED => (Nop, Implied),
            opcode::nop::unofficial3::IMPLIED => (Nop, Implied),
            opcode::nop::unofficial4::IMPLIED => (Nop, Implied),
            opcode::nop::unofficial5::IMPLIED => (Nop, Implied),
            opcode::ora::ABSOLUTE => (Ora, Absolute),
            opcode::ora::ABSOLUTE_X_INDEXED => (Ora, AbsoluteXIndexed),
            opcode::ora::ABSOLUTE_Y_INDEXED => (Ora, AbsoluteYIndexed),
            opcode::ora::IMMEDIATE => (Ora, Immediate),
            opcode::ora::INDIRECT_Y_INDEXED => (Ora, IndirectYIndexed),
            opcode::ora::X_INDEXED_INDIRECT => (Ora, XIndexedIndirect),
            opcode::ora::ZERO_PAGE => (Ora, ZeroPage),
            opcode::ora::ZERO_PAGE_X_INDEXED => (Ora, ZeroPageXIndexed),
            opcode::pha::IMPLIED => (Pha, Implied),
            opcode::php::IMPLIED => (Php, Implied),
            opcode::pla::IMPLIED => (Pla, Implied),
            opcode::plp::IMPLIED => (Plp, Implied),
            opcode::rla::unofficial0::X_INDEXED_INDIRECT => (Rla, XIndexedIndirect),
            opcode::rla::unofficial0::ZERO_PAGE => (Rla, ZeroPage),
            opcode::rla::unofficial0::ABSOLUTE => (Rla, Absolute),
            opcode::rla::unofficial0::INDIRECT_Y_INDEXED => (Rla, IndirectYIndexed),
            opcode::rla::unofficial0::ZERO_PAGE_X_INDEXED => (Rla, ZeroPageXIndexed),
            opcode::rla::unofficial0::ABSOLUTE_X_INDEXED => (Rla, AbsoluteXIndexed),
            opcode::rla::unofficial0::ABSOLUTE_Y_INDEXED => (Rla, AbsoluteYIndexed),
            opcode::rol::ABSOLUTE => (Rol, Absolute),
            opcode::rol::ABSOLUTE_X_INDEXED => (Rol, AbsoluteXIndexed),
            opcode::rol::ACCUMULATOR => (Rol, Accumulator),
            opcode::rol::ZERO_PAGE => (Rol, ZeroPage),
            opcode::rol::ZERO_PAGE_X_INDEXED => (Rol, ZeroPageXIndexed),
            opcode::ror::ABSOLUTE => (Ror, Absolute),
            opcode::ror::ABSOLUTE_X_INDEXED => (Ror, AbsoluteXIndexed),
            opcode::ror::ACCUMULATOR => (Ror, Accumulator),
            opcode::ror::ZERO_PAGE => (Ror, ZeroPage),
            opcode::ror::ZERO_PAGE_X_INDEXED => (Ror, ZeroPageXIndexed),
            opcode::rra::unofficial0::X_INDEXED_INDIRECT => (Rra, XIndexedIndirect),
            opcode::rra::unofficial0::ZERO_PAGE => (Rra, ZeroPage),
            opcode::rra::unofficial0::ABSOLUTE => (Rra, Absolute),
            opcode::rra::unofficial0::INDIRECT_Y_INDEXED => (Rra, IndirectYIndexed),
            opcode::rra::unofficial0::ZERO_PAGE_X_INDEXED => (Rra, ZeroPageXIndexed),
            opcode::rra::unofficial0::ABSOLUTE_X_INDEXED => (Rra, AbsoluteXIndexed),
            opcode::rra::unofficial0::ABSOLUTE_Y_INDEXED => (Rra, AbsoluteYIndexed),
            opcode::rti::IMPLIED => (Rti, Implied),
            opcode::rts::IMPLIED => (Rts, Implied),
            opcode::sax::unofficial0::X_INDEXED_INDIRECT => (Sax, XIndexedIndirect),
            opcode::sax::unofficial0::ZERO_PAGE => (Sax, ZeroPage),
            opcode::sax::unofficial0::ABSOLUTE => (Sax, Absolute),
            opcode::sax::unofficial0::ZERO_PAGE_Y_INDEXED => (Sax, ZeroPageYIndexed),
            opcode::sbc::ABSOLUTE => (Sbc, Absolute),
            opcode::sbc::ABSOLUTE_X_INDEXED => (Sbc, AbsoluteXIndexed),
            opcode::sbc::ABSOLUTE_Y_INDEXED => (Sbc, AbsoluteYIndexed),
            opcode::sbc::IMMEDIATE => (Sbc, Immediate),
            opcode::sbc::INDIRECT_Y_INDEXED => (Sbc, IndirectYIndexed),
            opcode::sbc::X_INDEXED_INDIRECT => (Sbc, XIndexedIndirect),
            opcode::sbc::ZERO_PAGE => (Sbc, ZeroPage),
            opcode::sbc::ZERO_PAGE_X_INDEXED => (Sbc, ZeroPageXIndexed),
            opcode::sbc::unofficial0::IMMEDIATE => (Sbc, Immediate),
            opcode::sec::IMPLIED => (Sec, Implied),
            opcode::sed::IMPLIED => (Sed, Implied),
            opcode::sei::IMPLIED => (Sei, Implied),
            opcode::skb::unofficial0::IMMEDIATE => (Skb, Immediate),
            opcode::skb::unofficial1::IMMEDIATE => (Skb, Immediate),
            opcode::skb::unofficial2::IMMEDIATE => (Skb, Immediate),
            opcode::skb::unofficial3::IMMEDIATE => (Skb, Immediate),
            opcode::skb::unofficial4::IMMEDIATE => (Skb, Immediate),
            opcode::slo::unofficial0::X_INDEXED_INDIRECT => (Slo, XIndexedIndirect),
            opcode::slo::unofficial0::ZERO_PAGE => (Slo, ZeroPage),
            opcode::slo::unofficial0::ABSOLUTE => (Slo, Absolute),
            opcode::slo::unofficial0::INDIRECT_Y_INDEXED => (Slo, IndirectYIndexed),
            opcode::slo::unofficial0::ZERO_PAGE_X_INDEXED => (Slo, ZeroPageXIndexed),
            opcode::slo::unofficial0::ABSOLUTE_X_INDEXED => (Slo, AbsoluteXIndexed),
            opcode::slo::unofficial0::ABSOLUTE_Y_INDEXED => (Slo, AbsoluteYIndexed),
            opcode::sre::unofficial0::X_INDEXED_INDIRECT => (Sre, XIndexedIndirect),
            opcode::sre::unofficial0::ZERO_PAGE => (Sre, ZeroPage),
            opcode::sre::unofficial0::ABSOLUTE => (Sre, Absolute),
            opcode::sre::unofficial0::INDIRECT_Y_INDEXED => (Sre, IndirectYIndexed),
            opcode::sre::unofficial0::ZERO_PAGE_X_INDEXED => (Sre, ZeroPageXIndexed),
            opcode::sre::unofficial0::ABSOLUTE_X_INDEXED => (Sre, AbsoluteXIndexed),
            opcode::sre::unofficial0::ABSOLUTE_Y_INDEXED => (Sre, AbsoluteYIndexed),
            opcode::sta::ABSOLUTE => (Sta, Absolute),
            opcode::sta::ABSOLUTE_X_INDEXED => (Sta, AbsoluteXIndexed),
            opcode::sta::ABSOLUTE_Y_INDEXED => (Sta, AbsoluteYIndexed),
            opcode::sta::INDIRECT_Y_INDEXED => (Sta, IndirectYIndexed),
            opcode::sta::X_INDEXED_INDIRECT => (Sta, XIndexedIndirect),
            opcode::sta::ZERO_PAGE => (Sta, ZeroPage),
            opcode::sta::ZERO_PAGE_X_INDEXED => (Sta, ZeroPageXIndexed),
            opcode::stx::ABSOLUTE => (Stx, Absolute),
            opcode::stx::ZERO_PAGE => (Stx, ZeroPage),
            opcode::stx::ZERO_PAGE_Y_INDEXED => (Stx, ZeroPageYIndexed),
            opcode::sty::ABSOLUTE => (Sty, Absolute),
            opcode::sty::ZERO_PAGE => (Sty, ZeroPage),
            opcode::sty::ZERO_PAGE_X_INDEXED => (Sty, ZeroPageXIndexed),
            opcode::sxa::unofficial0::ABSOLUTE_Y_INDEXED => (Sxa, AbsoluteYIndexed),
            opcode::sya::unofficial0::ABSOLUTE_X_INDEXED => (Sya, AbsoluteXIndexed),
            opcode::tax::IMPLIED => (Tax, Implied),
            opcode::tay::IMPLIED => (Tay, Implied),
            opcode::tsx::IMPLIED => (Tsx, Implied),
            opcode::txa::IMPLIED => (Txa, Implied),
            opcode::txs::IMPLIED => (Txs, Implied),
            opcode::tya::IMPLIED => (Tya, Implied),
            _ => return Err(UnknownOpcode(opcode)),
        };
        Ok(Instruction::new(instruction_type, addressing_mode))
    }
    pub fn instruction_type(&self) -> InstructionType {
        self.instruction_type
    }
    pub fn addressing_mode(&self) -> AddressingMode {
        self.addressing_mode
    }
}
#[derive(Debug, Clone)]
pub struct InstructionWithOperand {
    address: Address,
    instruction: Instruction,
    operand: Vec<u8>,
}
impl InstructionWithOperand {
    pub fn decode<M: MemoryReadOnly>(address: Address, memory: &M) -> Result<Self, UnknownOpcode> {
        let opcode = memory.read_u8_read_only(address);
        let instruction = Instruction::from_opcode(opcode)?;
        let operand_bytes = instruction.addressing_mode.operand_bytes();
        let mut operand = Vec::new();
        for i in 0..operand_bytes {
            operand
                .push(memory.read_u8_read_only(address.wrapping_add(i as Address).wrapping_add(1)));
        }
        Ok(Self {
            address,
            instruction,
            operand,
        })
    }
    pub fn next<M: MemoryReadOnly>(cpu: &Cpu, memory: &M) -> Result<Self, UnknownOpcode> {
        Self::decode(cpu.pc, memory)
    }
    pub fn instruction(&self) -> Instruction {
        self.instruction
    }
    pub fn operand_u16_le(&self) -> Option<u16> {
        match self.operand.as_slice() {
            &[_x] => None,
            &[x0, x1] => Some((x1 as u16) << 8 | x0 as u16),
            _ => None,
        }
    }
    pub fn address(&self) -> Address {
        self.address
    }
}
impl fmt::Display for InstructionWithOperand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{:04X}  {:?}({:?}) ",
            self.address, self.instruction.instruction_type, self.instruction.addressing_mode
        )?;
        match self.operand.as_slice() {
            &[x] => write!(f, "{:02X}", x)?,
            &[x0, x1] => write!(f, "{:04X}", (x1 as u16) << 8 | x0 as u16)?,
            _ => (),
        }
        Ok(())
    }
}