1#![no_std]
2
3#[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 AddressDiff::from_const(self.operand.width() + 1)
49 }
50}
51
52impl yaxpeax_arch::Instruction for Instruction {
53 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
170impl 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 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}