yaxpeax_6502/
lib.rs

1#![no_std]
2
3/** References: https://www.masswerk.at/6502/6502_instruction_set.html
4*/
5
6#[cfg(feature = "std")]
7extern crate std;
8
9use yaxpeax_arch::{AddressDiff, Arch, Decoder, LengthedInstruction, Reader};
10
11mod display;
12
13#[derive(Debug)]
14pub struct N6502;
15
16impl Arch for N6502 {
17    type Address = u16;
18    type Word = u8;
19    type Instruction = Instruction;
20    type DecodeError = DecodeError;
21    type Decoder = InstDecoder;
22    type Operand = Operand;
23}
24
25#[derive(Debug, Copy, Clone)]
26pub struct Instruction {
27    pub opcode: Opcode,
28    pub operand: Operand,
29}
30
31impl Default for Instruction {
32    fn default() -> Self {
33        Instruction {
34            opcode: Opcode::Invalid(0xff),
35            operand: Operand::Implied,
36        }
37    }
38}
39
40impl LengthedInstruction for Instruction {
41    type Unit = AddressDiff<<N6502 as Arch>::Address>;
42    fn min_size() -> Self::Unit {
43        AddressDiff::from_const(1)
44    }
45
46    fn len(&self) -> Self::Unit {
47        // Each opcode is 1 byte, remaining insn size inherent in operand.
48        AddressDiff::from_const(self.operand.width() + 1)
49    }
50}
51
52impl yaxpeax_arch::Instruction for Instruction {
53    // FIXME: Probably not correct.
54    fn well_defined(&self) -> bool {
55        true
56    }
57}
58
59#[derive(Debug, Copy, Clone)]
60pub enum Width {
61    W,
62    B,
63    None,
64}
65
66#[derive(Debug, Copy, Clone, PartialEq)]
67pub enum Opcode {
68    Invalid(u8),
69    ADC,
70    AND,
71    ASL,
72    BCC,
73    BCS,
74    BEQ,
75    BIT,
76    BMI,
77    BNE,
78    BPL,
79    BRK,
80    BVC,
81    BVS,
82    CLC,
83    CLD,
84    CLI,
85    CLV,
86    CMP,
87    CPX,
88    CPY,
89    DEC,
90    DEX,
91    DEY,
92    EOR,
93    INC,
94    INX,
95    INY,
96    JMP,
97    JSR,
98    LDA,
99    LDX,
100    LDY,
101    LSR,
102    NOP,
103    ORA,
104    PHA,
105    PHP,
106    PLA,
107    PLP,
108    ROL,
109    ROR,
110    RTI,
111    RTS,
112    SBC,
113    SEC,
114    SED,
115    SEI,
116    STA,
117    STX,
118    STY,
119    TAX,
120    TAY,
121    TSX,
122    TXA,
123    TXS,
124    TYA,
125}
126
127#[derive(Debug, Copy, Clone)]
128pub enum Operand {
129    Accumulator,
130    Absolute(u16),
131    AbsoluteX(u16),
132    AbsoluteY(u16),
133    Immediate(u8),
134    Implied,
135    Indirect(u16),
136    IndirectYIndexed(u8),
137    XIndexedIndirect(u8),
138    Relative(u8),
139    ZeroPage(u8),
140    ZeroPageX(u8),
141    ZeroPageY(u8),
142}
143
144impl Operand {
145    fn width(&self) -> <N6502 as Arch>::Address {
146        match self {
147            Operand::Accumulator | Operand::Implied => 0,
148
149            Operand::Immediate(_)
150            | Operand::IndirectYIndexed(_)
151            | Operand::XIndexedIndirect(_)
152            | Operand::Relative(_)
153            | Operand::ZeroPage(_)
154            | Operand::ZeroPageX(_)
155            | Operand::ZeroPageY(_) => 1,
156
157            Operand::Absolute(_)
158            | Operand::AbsoluteX(_)
159            | Operand::AbsoluteY(_)
160            | Operand::Indirect(_) => 2,
161        }
162    }
163}
164
165pub type DecodeError = yaxpeax_arch::StandardDecodeError;
166
167#[derive(Debug)]
168pub struct InstDecoder;
169
170/** An inherent implementation of `InstDecoder` is made public in case I want to use each part of
171    the decoder individually, such as in a cycle-accurate emulator.
172*/
173impl InstDecoder {
174    pub fn op_type(&self, opcode: u8) -> Result<(Opcode, Operand), DecodeError> {
175        match opcode {
176            0x00 => Ok((Opcode::BRK, Operand::Implied)),
177            0x01 => Ok((Opcode::ORA, Operand::XIndexedIndirect(Default::default()))),
178            0x05 => Ok((Opcode::ORA, Operand::ZeroPage(Default::default()))),
179            0x06 => Ok((Opcode::ASL, Operand::ZeroPage(Default::default()))),
180            0x08 => Ok((Opcode::PHP, Operand::Implied)),
181            0x09 => Ok((Opcode::ORA, Operand::Immediate(Default::default()))),
182            0x0a => Ok((Opcode::ASL, Operand::Accumulator)),
183            0x0d => Ok((Opcode::ORA, Operand::Absolute(Default::default()))),
184            0x0e => Ok((Opcode::ASL, Operand::Absolute(Default::default()))),
185
186            0x10 => Ok((Opcode::BPL, Operand::Relative(Default::default()))),
187            0x11 => Ok((Opcode::ORA, Operand::IndirectYIndexed(Default::default()))),
188            0x15 => Ok((Opcode::ORA, Operand::ZeroPageX(Default::default()))),
189            0x16 => Ok((Opcode::ASL, Operand::ZeroPageX(Default::default()))),
190            0x18 => Ok((Opcode::CLC, Operand::Implied)),
191            0x19 => Ok((Opcode::ORA, Operand::AbsoluteY(Default::default()))),
192            0x1d => Ok((Opcode::ORA, Operand::AbsoluteX(Default::default()))),
193            0x1e => Ok((Opcode::ASL, Operand::AbsoluteX(Default::default()))),
194
195            0x20 => Ok((Opcode::JSR, Operand::Absolute(Default::default()))),
196            0x21 => Ok((Opcode::AND, Operand::XIndexedIndirect(Default::default()))),
197            0x24 => Ok((Opcode::BIT, Operand::ZeroPage(Default::default()))),
198            0x25 => Ok((Opcode::AND, Operand::ZeroPage(Default::default()))),
199            0x26 => Ok((Opcode::ROL, Operand::ZeroPage(Default::default()))),
200            0x28 => Ok((Opcode::PLP, Operand::Implied)),
201            0x29 => Ok((Opcode::AND, Operand::Immediate(Default::default()))),
202            0x2a => Ok((Opcode::ROL, Operand::Accumulator)),
203            0x2c => Ok((Opcode::BIT, Operand::Absolute(Default::default()))),
204            0x2d => Ok((Opcode::AND, Operand::Absolute(Default::default()))),
205            0x2e => Ok((Opcode::ROL, Operand::Absolute(Default::default()))),
206
207            0x30 => Ok((Opcode::BMI, Operand::Relative(Default::default()))),
208            0x31 => Ok((Opcode::AND, Operand::IndirectYIndexed(Default::default()))),
209            0x35 => Ok((Opcode::AND, Operand::ZeroPageX(Default::default()))),
210            0x36 => Ok((Opcode::ROL, Operand::ZeroPageX(Default::default()))),
211            0x38 => Ok((Opcode::SEC, Operand::Implied)),
212            0x39 => Ok((Opcode::AND, Operand::AbsoluteY(Default::default()))),
213            0x3d => Ok((Opcode::AND, Operand::AbsoluteX(Default::default()))),
214            0x3e => Ok((Opcode::ROL, Operand::AbsoluteX(Default::default()))),
215
216            0x40 => Ok((Opcode::RTI, Operand::Implied)),
217            0x41 => Ok((Opcode::EOR, Operand::XIndexedIndirect(Default::default()))),
218            0x45 => Ok((Opcode::EOR, Operand::ZeroPage(Default::default()))),
219            0x46 => Ok((Opcode::LSR, Operand::ZeroPage(Default::default()))),
220            0x48 => Ok((Opcode::PHA, Operand::Implied)),
221            0x49 => Ok((Opcode::EOR, Operand::Immediate(Default::default()))),
222            0x4a => Ok((Opcode::LSR, Operand::Accumulator)),
223            0x4c => Ok((Opcode::JMP, Operand::Absolute(Default::default()))),
224            0x4d => Ok((Opcode::EOR, Operand::Absolute(Default::default()))),
225            0x4e => Ok((Opcode::LSR, Operand::Absolute(Default::default()))),
226
227            0x50 => Ok((Opcode::BVC, Operand::Relative(Default::default()))),
228            0x51 => Ok((Opcode::EOR, Operand::IndirectYIndexed(Default::default()))),
229            0x55 => Ok((Opcode::EOR, Operand::ZeroPageX(Default::default()))),
230            0x56 => Ok((Opcode::LSR, Operand::ZeroPageX(Default::default()))),
231            0x58 => Ok((Opcode::CLI, Operand::Implied)),
232            0x59 => Ok((Opcode::EOR, Operand::AbsoluteY(Default::default()))),
233            0x5d => Ok((Opcode::EOR, Operand::AbsoluteX(Default::default()))),
234            0x5e => Ok((Opcode::LSR, Operand::AbsoluteX(Default::default()))),
235
236            0x60 => Ok((Opcode::RTS, Operand::Implied)),
237            0x61 => Ok((Opcode::ADC, Operand::XIndexedIndirect(Default::default()))),
238            0x65 => Ok((Opcode::ADC, Operand::ZeroPage(Default::default()))),
239            0x66 => Ok((Opcode::ROR, Operand::ZeroPage(Default::default()))),
240            0x68 => Ok((Opcode::PLA, Operand::Implied)),
241            0x69 => Ok((Opcode::ADC, Operand::Immediate(Default::default()))),
242            0x6a => Ok((Opcode::ROR, Operand::Accumulator)),
243            0x6c => Ok((Opcode::JMP, Operand::Indirect(Default::default()))),
244            0x6d => Ok((Opcode::ADC, Operand::Absolute(Default::default()))),
245            0x6e => Ok((Opcode::ROR, Operand::Absolute(Default::default()))),
246
247            0x70 => Ok((Opcode::BVS, Operand::Relative(Default::default()))),
248            0x71 => Ok((Opcode::ADC, Operand::IndirectYIndexed(Default::default()))),
249            0x75 => Ok((Opcode::ADC, Operand::ZeroPageX(Default::default()))),
250            0x76 => Ok((Opcode::ROR, Operand::ZeroPageX(Default::default()))),
251            0x78 => Ok((Opcode::SEI, Operand::Implied)),
252            0x79 => Ok((Opcode::ADC, Operand::AbsoluteY(Default::default()))),
253            0x7d => Ok((Opcode::ADC, Operand::AbsoluteX(Default::default()))),
254            0x7e => Ok((Opcode::ROR, Operand::AbsoluteX(Default::default()))),
255
256            /* 0x80 */
257            0x81 => Ok((Opcode::STA, Operand::XIndexedIndirect(Default::default()))),
258            0x84 => Ok((Opcode::STY, Operand::ZeroPage(Default::default()))),
259            0x85 => Ok((Opcode::STA, Operand::ZeroPage(Default::default()))),
260            0x86 => Ok((Opcode::STX, Operand::ZeroPage(Default::default()))),
261            0x88 => Ok((Opcode::DEY, Operand::Implied)),
262            0x8a => Ok((Opcode::TXA, Operand::Implied)),
263            0x8c => Ok((Opcode::STY, Operand::Absolute(Default::default()))),
264            0x8d => Ok((Opcode::STA, Operand::Absolute(Default::default()))),
265            0x8e => Ok((Opcode::STX, Operand::Absolute(Default::default()))),
266
267            0x90 => Ok((Opcode::BCC, Operand::Relative(Default::default()))),
268            0x91 => Ok((Opcode::STA, Operand::IndirectYIndexed(Default::default()))),
269            0x94 => Ok((Opcode::STY, Operand::ZeroPageX(Default::default()))),
270            0x95 => Ok((Opcode::STA, Operand::ZeroPageX(Default::default()))),
271            0x96 => Ok((Opcode::STX, Operand::ZeroPageY(Default::default()))),
272            0x98 => Ok((Opcode::TYA, Operand::Implied)),
273            0x99 => Ok((Opcode::STA, Operand::AbsoluteY(Default::default()))),
274            0x9a => Ok((Opcode::TXS, Operand::Implied)),
275            0x9d => Ok((Opcode::STA, Operand::AbsoluteX(Default::default()))),
276
277            0xa0 => Ok((Opcode::LDY, Operand::Immediate(Default::default()))),
278            0xa1 => Ok((Opcode::LDA, Operand::XIndexedIndirect(Default::default()))),
279            0xa2 => Ok((Opcode::LDX, Operand::Immediate(Default::default()))),
280            0xa4 => Ok((Opcode::LDY, Operand::ZeroPage(Default::default()))),
281            0xa5 => Ok((Opcode::LDA, Operand::ZeroPage(Default::default()))),
282            0xa6 => Ok((Opcode::LDX, Operand::ZeroPage(Default::default()))),
283            0xa8 => Ok((Opcode::TAY, Operand::Implied)),
284            0xa9 => Ok((Opcode::LDA, Operand::Immediate(Default::default()))),
285            0xaa => Ok((Opcode::TAX, Operand::Implied)),
286            0xac => Ok((Opcode::LDY, Operand::Absolute(Default::default()))),
287            0xad => Ok((Opcode::LDA, Operand::Absolute(Default::default()))),
288            0xae => Ok((Opcode::LDX, Operand::Absolute(Default::default()))),
289
290            0xb0 => Ok((Opcode::BCS, Operand::Relative(Default::default()))),
291            0xb1 => Ok((Opcode::LDA, Operand::IndirectYIndexed(Default::default()))),
292            0xb4 => Ok((Opcode::LDY, Operand::ZeroPageX(Default::default()))),
293            0xb5 => Ok((Opcode::LDA, Operand::ZeroPageX(Default::default()))),
294            0xb6 => Ok((Opcode::LDX, Operand::ZeroPageY(Default::default()))),
295            0xb8 => Ok((Opcode::CLV, Operand::Implied)),
296            0xb9 => Ok((Opcode::LDA, Operand::AbsoluteY(Default::default()))),
297            0xba => Ok((Opcode::TSX, Operand::Implied)),
298            0xbc => Ok((Opcode::LDY, Operand::AbsoluteX(Default::default()))),
299            0xbd => Ok((Opcode::LDA, Operand::AbsoluteX(Default::default()))),
300            0xbe => Ok((Opcode::LDX, Operand::AbsoluteY(Default::default()))),
301
302            0xc0 => Ok((Opcode::CPY, Operand::Immediate(Default::default()))),
303            0xc1 => Ok((Opcode::CMP, Operand::XIndexedIndirect(Default::default()))),
304            0xc4 => Ok((Opcode::CPY, Operand::ZeroPage(Default::default()))),
305            0xc5 => Ok((Opcode::CMP, Operand::ZeroPage(Default::default()))),
306            0xc6 => Ok((Opcode::DEC, Operand::ZeroPage(Default::default()))),
307            0xc8 => Ok((Opcode::INY, Operand::Implied)),
308            0xc9 => Ok((Opcode::CMP, Operand::Immediate(Default::default()))),
309            0xca => Ok((Opcode::DEX, Operand::Implied)),
310            0xcc => Ok((Opcode::CPY, Operand::Absolute(Default::default()))),
311            0xcd => Ok((Opcode::CMP, Operand::Absolute(Default::default()))),
312            0xce => Ok((Opcode::DEC, Operand::Absolute(Default::default()))),
313
314            0xd0 => Ok((Opcode::BNE, Operand::Relative(Default::default()))),
315            0xd1 => Ok((Opcode::CMP, Operand::IndirectYIndexed(Default::default()))),
316            0xd5 => Ok((Opcode::CMP, Operand::ZeroPageX(Default::default()))),
317            0xd6 => Ok((Opcode::DEC, Operand::ZeroPageX(Default::default()))),
318            0xd8 => Ok((Opcode::CLD, Operand::Implied)),
319            0xd9 => Ok((Opcode::CMP, Operand::AbsoluteY(Default::default()))),
320            0xdd => Ok((Opcode::CMP, Operand::AbsoluteX(Default::default()))),
321            0xde => Ok((Opcode::DEC, Operand::AbsoluteX(Default::default()))),
322
323            0xe0 => Ok((Opcode::CPX, Operand::Immediate(Default::default()))),
324            0xe1 => Ok((Opcode::SBC, Operand::XIndexedIndirect(Default::default()))),
325            0xe4 => Ok((Opcode::CPX, Operand::ZeroPage(Default::default()))),
326            0xe5 => Ok((Opcode::SBC, Operand::ZeroPage(Default::default()))),
327            0xe6 => Ok((Opcode::INC, Operand::ZeroPage(Default::default()))),
328            0xe8 => Ok((Opcode::INX, Operand::Implied)),
329            0xe9 => Ok((Opcode::SBC, Operand::Immediate(Default::default()))),
330            0xea => Ok((Opcode::NOP, Operand::Implied)),
331            0xec => Ok((Opcode::CPX, Operand::Absolute(Default::default()))),
332            0xed => Ok((Opcode::SBC, Operand::Absolute(Default::default()))),
333            0xee => Ok((Opcode::INC, Operand::Absolute(Default::default()))),
334
335            0xf0 => Ok((Opcode::BEQ, Operand::Relative(Default::default()))),
336            0xf1 => Ok((Opcode::SBC, Operand::IndirectYIndexed(Default::default()))),
337            0xf5 => Ok((Opcode::SBC, Operand::ZeroPageX(Default::default()))),
338            0xf6 => Ok((Opcode::INC, Operand::ZeroPageX(Default::default()))),
339            0xf8 => Ok((Opcode::SED, Operand::Implied)),
340            0xf9 => Ok((Opcode::SBC, Operand::AbsoluteY(Default::default()))),
341            0xfd => Ok((Opcode::SBC, Operand::AbsoluteX(Default::default()))),
342            0xfe => Ok((Opcode::INC, Operand::AbsoluteX(Default::default()))),
343
344            _ => Err(DecodeError::InvalidOpcode),
345        }
346    }
347}
348
349impl Default for InstDecoder {
350    fn default() -> Self {
351        InstDecoder {}
352    }
353}
354
355impl Decoder<N6502> for InstDecoder {
356    fn decode_into<T: Reader<<N6502 as Arch>::Address, <N6502 as Arch>::Word>>(
357        &self,
358        inst: &mut Instruction,
359        words: &mut T,
360    ) -> Result<(), <N6502 as Arch>::DecodeError> {
361        let opcode = words.next()?;
362
363        let (op_type, operand) = self.op_type(opcode).map_err(|e| {
364            inst.opcode = Opcode::Invalid(opcode);
365            e
366        })?;
367
368        let mut op_byte: u8 = 0;
369        let mut op_word: u16 = 0;
370
371        match operand.width() {
372            0 => {}
373            1 => {
374                op_byte = words.next()?;
375            }
376            2 => {
377                let byte_lo = words.next()?;
378                let byte_hi = words.next()?;
379
380                op_word = u16::from_le_bytes([byte_lo, byte_hi]);
381            }
382            _ => {
383                unreachable!()
384            }
385        }
386
387        let operand = match operand {
388            Operand::Accumulator => Operand::Accumulator,
389            Operand::Implied => Operand::Implied,
390
391            Operand::Immediate(_) => Operand::Immediate(op_byte),
392            Operand::IndirectYIndexed(_) => Operand::IndirectYIndexed(op_byte),
393            Operand::XIndexedIndirect(_) => Operand::XIndexedIndirect(op_byte),
394            Operand::Relative(_) => Operand::Relative(op_byte),
395            Operand::ZeroPage(_) => Operand::ZeroPage(op_byte),
396            Operand::ZeroPageX(_) => Operand::ZeroPageX(op_byte),
397            Operand::ZeroPageY(_) => Operand::ZeroPageY(op_byte),
398
399            Operand::Absolute(_) => Operand::Absolute(op_word),
400            Operand::AbsoluteX(_) => Operand::AbsoluteX(op_word),
401            Operand::AbsoluteY(_) => Operand::AbsoluteY(op_word),
402            Operand::Indirect(_) => Operand::Indirect(op_word),
403        };
404
405        inst.opcode = op_type;
406        inst.operand = operand;
407
408        Ok(())
409    }
410}