alu.rsannotatedalu.rssource656 lines · 22.9 KB · raw
1#[allow(clippy::wildcard_imports)]
2use super::*;
3
4fn adc_bcd(registers: &mut Registers, value: u8) {
5    // Formulas from http://www.6502.org/tutorials/decimal_mode.html#A which correctly handle
6    // invalid values and undocumented behaviors
7
8    let original_a = registers.a as u8;
9    let existing_carry: u8 = registers.p.carry.into();
10
11    let mut al = (original_a & 0x0F) + (value & 0x0F) + existing_carry;
12    if al >= 0x0A {
13        al = 0x10 | ((al + 0x06) & 0x0F);
14    }
15
16    let mut a = u16::from(original_a & 0xF0) + u16::from(value & 0xF0) + u16::from(al);
17    if a >= 0xA0 {
18        a += 0x60;
19    }
20
21    let s = i16::from((original_a & 0xF0) as i8) + i16::from((value & 0xF0) as i8) + i16::from(al);
22    let overflow = !(-128..128).contains(&s);
23
24    let result = a as u8;
25    registers.a.set_lsb(result);
26
27    registers.p.zero = result == 0;
28    registers.p.carry = a >= 0x0100;
29    registers.p.negative = result.sign_bit();
30    registers.p.overflow = overflow;
31}
32
33fn adc_bcd_u16(registers: &mut Registers, value: u16) {
34    let [value_lsb, value_msb] = value.to_le_bytes();
35
36    adc_bcd(registers, value_lsb);
37    registers.a = registers.a.swap_bytes();
38    adc_bcd(registers, value_msb);
39    registers.a = registers.a.swap_bytes();
40
41    registers.p.zero = registers.a == 0;
42}
43
44fn sbc_bcd(registers: &mut Registers, value: u8) {
45    // Formulas from http://www.6502.org/tutorials/decimal_mode.html#A which correctly handle
46    // invalid values and undocumented behaviors
47
48    let original_a = registers.a as u8;
49    let existing_borrow: u8 = (!registers.p.carry).into();
50
51    let mut al = u16::from(original_a & 0x0F)
52        .wrapping_sub(u16::from(value & 0x0F))
53        .wrapping_sub(u16::from(existing_borrow));
54    if al.sign_bit() {
55        al = (al.wrapping_sub(0x06) & 0x0F).wrapping_sub(0x10);
56    }
57
58    let mut a = u16::from(original_a & 0xF0).wrapping_sub(u16::from(value & 0xF0)).wrapping_add(al);
59    if a.sign_bit() {
60        a = a.wrapping_sub(0x60);
61    }
62
63    // Carry and overflow flags are set based on binary arithmetic
64    let borrow = u16::from(original_a) < u16::from(value) + u16::from(existing_borrow);
65    let bit_6_borrow = original_a & 0x7F < (value & 0x7F) + existing_borrow;
66    let overflow = bit_6_borrow != borrow;
67
68    let result = a as u8;
69    registers.a.set_lsb(result);
70
71    registers.p.zero = result == 0;
72    registers.p.negative = result.sign_bit();
73    registers.p.carry = !borrow;
74    registers.p.overflow = overflow;
75}
76
77fn sbc_bcd_u16(registers: &mut Registers, value: u16) {
78    let [value_lsb, value_msb] = value.to_le_bytes();
79
80    sbc_bcd(registers, value_lsb);
81    registers.a = registers.a.swap_bytes();
82    sbc_bcd(registers, value_msb);
83    registers.a = registers.a.swap_bytes();
84
85    registers.p.zero = registers.a == 0;
86}

ADC: Add with carry (8-bit)

89impl_read_op_u8!(
90    [
91        immediate -> adc_immediate_u8,
92        direct_page -> adc_direct_page_u8,
93        direct_page_x -> adc_direct_page_x_u8,
94        direct_page_indirect -> adc_direct_page_indirect_u8,
95        direct_page_indexed_indirect -> adc_direct_page_indexed_indirect_u8,
96        direct_page_indirect_indexed -> adc_direct_page_indirect_indexed_u8,
97        direct_page_indirect_long -> adc_direct_page_indirect_long_u8,
98        direct_page_indirect_long_indexed -> adc_direct_page_indirect_long_indexed_u8,
99        absolute -> adc_absolute_u8,
100        absolute_x -> adc_absolute_x_u8,
101        absolute_y -> adc_absolute_y_u8,
102        absolute_long -> adc_absolute_long_u8,
103        absolute_long_x -> adc_absolute_long_x_u8,
104        stack_relative -> adc_stack_relative_u8,
105        stack_relative_indirect_indexed -> adc_stack_relative_indirect_indexed_u8,
106    ]
107    (|registers, value| {
108        if registers.p.decimal_mode {
109            adc_bcd(registers, value);
110            return;
111        }
112
113        let a = registers.a as u8;
114        let existing_carry: u8 = registers.p.carry.into();
115
116        let (partial_sum, carry1) = a.overflowing_add(value);
117        let (sum, carry2) = partial_sum.overflowing_add(existing_carry);
118        let carry = carry1 || carry2;
119
120        let bit_6_carry = (a & 0x7F) + (value & 0x7F) + existing_carry >= 0x80;
121        let overflow = bit_6_carry != carry;
122
123        registers.a.set_lsb(sum);
124
125        registers.p.zero = sum == 0;
126        registers.p.negative = sum.sign_bit();
127        registers.p.carry = carry;
128        registers.p.overflow = overflow;
129    })
130);

ADC: Add with carry (16-bit)

133impl_read_op_u16!(
134    [
135        immediate -> adc_immediate_u16,
136        direct_page -> adc_direct_page_u16,
137        direct_page_x -> adc_direct_page_x_u16,
138        direct_page_indirect -> adc_direct_page_indirect_u16,
139        direct_page_indexed_indirect -> adc_direct_page_indexed_indirect_u16,
140        direct_page_indirect_indexed -> adc_direct_page_indirect_indexed_u16,
141        direct_page_indirect_long -> adc_direct_page_indirect_long_u16,
142        direct_page_indirect_long_indexed -> adc_direct_page_indirect_long_indexed_u16,
143        absolute -> adc_absolute_u16,
144        absolute_x -> adc_absolute_x_u16,
145        absolute_y -> adc_absolute_y_u16,
146        absolute_long -> adc_absolute_long_u16,
147        absolute_long_x -> adc_absolute_long_x_u16,
148        stack_relative -> adc_stack_relative_u16,
149        stack_relative_indirect_indexed -> adc_stack_relative_indirect_indexed_u16,
150    ]
151    (|registers, value| {
152        if registers.p.decimal_mode {
153            adc_bcd_u16(registers, value);
154            return;
155        }
156
157        let a = registers.a;
158        let existing_carry: u16 = registers.p.carry.into();
159
160        let (partial_sum, carry1) = a.overflowing_add(value);
161        let (sum, carry2) = partial_sum.overflowing_add(existing_carry);
162        let carry = carry1 || carry2;
163
164        let bit_14_carry = (a & 0x7FFF) + (value & 0x7FFF) + existing_carry >= 0x8000;
165        let overflow = bit_14_carry != carry;
166
167        registers.a = sum;
168
169        registers.p.zero = sum == 0;
170        registers.p.negative = sum.sign_bit();
171        registers.p.carry = carry;
172        registers.p.overflow = overflow;
173    })
174);

SBC: Subtract with carry (8-bit)

177impl_read_op_u8!(
178    [
179        immediate -> sbc_immediate_u8,
180        direct_page -> sbc_direct_page_u8,
181        direct_page_x -> sbc_direct_page_x_u8,
182        direct_page_indirect -> sbc_direct_page_indirect_u8,
183        direct_page_indexed_indirect -> sbc_direct_page_indexed_indirect_u8,
184        direct_page_indirect_indexed -> sbc_direct_page_indirect_indexed_u8,
185        direct_page_indirect_long -> sbc_direct_page_indirect_long_u8,
186        direct_page_indirect_long_indexed -> sbc_direct_page_indirect_long_indexed_u8,
187        absolute -> sbc_absolute_u8,
188        absolute_x -> sbc_absolute_x_u8,
189        absolute_y -> sbc_absolute_y_u8,
190        absolute_long -> sbc_absolute_long_u8,
191        absolute_long_x -> sbc_absolute_long_x_u8,
192        stack_relative -> sbc_stack_relative_u8,
193        stack_relative_indirect_indexed -> sbc_stack_relative_indirect_indexed_u8,
194    ]
195    (|registers, value| {
196        if registers.p.decimal_mode {
197            sbc_bcd(registers, value);
198            return;
199        }
200
201        let a = registers.a as u8;
202        let existing_borrow: u8 = (!registers.p.carry).into();
203
204        let (partial_diff, borrow1) = a.overflowing_sub(value);
205        let (difference, borrow2) = partial_diff.overflowing_sub(existing_borrow);
206        let borrow = borrow1 || borrow2;
207
208        let bit_6_borrow = a & 0x7F < (value & 0x7F) + existing_borrow;
209        let overflow = bit_6_borrow != borrow;
210
211        registers.a.set_lsb(difference);
212
213        registers.p.zero = difference == 0;
214        registers.p.negative = difference.sign_bit();
215        registers.p.carry = !borrow;
216        registers.p.overflow = overflow;
217    })
218);

SBC: Subtract with carry (16-bit)

221impl_read_op_u16!(
222    [
223        immediate -> sbc_immediate_u16,
224        direct_page -> sbc_direct_page_u16,
225        direct_page_x -> sbc_direct_page_x_u16,
226        direct_page_indirect -> sbc_direct_page_indirect_u16,
227        direct_page_indexed_indirect -> sbc_direct_page_indexed_indirect_u16,
228        direct_page_indirect_indexed -> sbc_direct_page_indirect_indexed_u16,
229        direct_page_indirect_long -> sbc_direct_page_indirect_long_u16,
230        direct_page_indirect_long_indexed -> sbc_direct_page_indirect_long_indexed_u16,
231        absolute -> sbc_absolute_u16,
232        absolute_x -> sbc_absolute_x_u16,
233        absolute_y -> sbc_absolute_y_u16,
234        absolute_long -> sbc_absolute_long_u16,
235        absolute_long_x -> sbc_absolute_long_x_u16,
236        stack_relative -> sbc_stack_relative_u16,
237        stack_relative_indirect_indexed -> sbc_stack_relative_indirect_indexed_u16,
238    ]
239    (|registers, value| {
240        if registers.p.decimal_mode {
241            sbc_bcd_u16(registers, value);
242            return;
243        }
244
245        let a = registers.a;
246        let existing_borrow: u16 = (!registers.p.carry).into();
247
248        let (partial_diff, borrow1) = a.overflowing_sub(value);
249        let (difference, borrow2) = partial_diff.overflowing_sub(existing_borrow);
250        let borrow = borrow1 || borrow2;
251
252        let bit_14_borrow = a & 0x7FFF < (value & 0x7FFF) + existing_borrow;
253        let overflow = bit_14_borrow != borrow;
254
255        registers.a = difference;
256
257        registers.p.zero = difference == 0;
258        registers.p.negative = difference.sign_bit();
259        registers.p.carry = !borrow;
260        registers.p.overflow = overflow;
261    })
262);

CMP: Compare to accumulator (8-bit)

265impl_read_op_u8!(
266    [
267        immediate -> cmp_immediate_u8,
268        direct_page -> cmp_direct_page_u8,
269        direct_page_x -> cmp_direct_page_x_u8,
270        direct_page_indirect -> cmp_direct_page_indirect_u8,
271        direct_page_indexed_indirect -> cmp_direct_page_indexed_indirect_u8,
272        direct_page_indirect_indexed -> cmp_direct_page_indirect_indexed_u8,
273        direct_page_indirect_long -> cmp_direct_page_indirect_long_u8,
274        direct_page_indirect_long_indexed -> cmp_direct_page_indirect_long_indexed_u8,
275        absolute -> cmp_absolute_u8,
276        absolute_x -> cmp_absolute_x_u8,
277        absolute_y -> cmp_absolute_y_u8,
278        absolute_long -> cmp_absolute_long_u8,
279        absolute_long_x -> cmp_absolute_long_x_u8,
280        stack_relative -> cmp_stack_relative_u8,
281        stack_relative_indirect_indexed -> cmp_stack_relative_indirect_indexed_u8,
282    ]
283    (|registers, value| {
284        let (difference, borrow) = (registers.a as u8).overflowing_sub(value);
285
286        registers.p.carry = !borrow;
287        registers.p.zero = difference == 0;
288        registers.p.negative = difference.sign_bit();
289    })
290);

CMP: Compare to accumulator (16-bit)

293impl_read_op_u16!(
294    [
295        immediate -> cmp_immediate_u16,
296        direct_page -> cmp_direct_page_u16,
297        direct_page_x -> cmp_direct_page_x_u16,
298        direct_page_indirect -> cmp_direct_page_indirect_u16,
299        direct_page_indexed_indirect -> cmp_direct_page_indexed_indirect_u16,
300        direct_page_indirect_indexed -> cmp_direct_page_indirect_indexed_u16,
301        direct_page_indirect_long -> cmp_direct_page_indirect_long_u16,
302        direct_page_indirect_long_indexed -> cmp_direct_page_indirect_long_indexed_u16,
303        absolute -> cmp_absolute_u16,
304        absolute_x -> cmp_absolute_x_u16,
305        absolute_y -> cmp_absolute_y_u16,
306        absolute_long -> cmp_absolute_long_u16,
307        absolute_long_x -> cmp_absolute_long_x_u16,
308        stack_relative -> cmp_stack_relative_u16,
309        stack_relative_indirect_indexed -> cmp_stack_relative_indirect_indexed_u16,
310    ]
311    (|registers, value| {
312        let (difference, borrow) = registers.a.overflowing_sub(value);
313
314        registers.p.carry = !borrow;
315        registers.p.zero = difference == 0;
316        registers.p.negative = difference.sign_bit();
317    })
318);

CPX: Compare to X register (8-bit)

321impl_read_op_u8!(
322    [
323        immediate -> cpx_immediate_u8,
324        direct_page -> cpx_direct_page_u8,
325        absolute -> cpx_absolute_u8,
326    ]
327    (|registers, value| {
328        let (difference, borrow) = (registers.x as u8).overflowing_sub(value);
329
330        registers.p.carry = !borrow;
331        registers.p.zero = difference == 0;
332        registers.p.negative = difference.sign_bit();
333    })
334);

CPX: Compare to X register (16-bit)

337impl_read_op_u16!(
338    [
339        immediate -> cpx_immediate_u16,
340        direct_page -> cpx_direct_page_u16,
341        absolute -> cpx_absolute_u16,
342    ]
343    (|registers, value| {
344        let (difference, borrow) = registers.x.overflowing_sub(value);
345
346        registers.p.carry = !borrow;
347        registers.p.zero = difference == 0;
348        registers.p.negative = difference.sign_bit();
349    })
350);

CPY: Compare to Y register (8-bit)

353impl_read_op_u8!(
354    [
355        immediate -> cpy_immediate_u8,
356        direct_page -> cpy_direct_page_u8,
357        absolute -> cpy_absolute_u8,
358    ]
359    (|registers, value| {
360        let (difference, borrow) = (registers.y as u8).overflowing_sub(value);
361
362        registers.p.carry = !borrow;
363        registers.p.zero = difference == 0;
364        registers.p.negative = difference.sign_bit();
365    })
366);

CPY: Compare to Y register (16-bit)

369impl_read_op_u16!(
370    [
371        immediate -> cpy_immediate_u16,
372        direct_page -> cpy_direct_page_u16,
373        absolute -> cpy_absolute_u16,
374    ]
375    (|registers, value| {
376        let (difference, borrow) = registers.y.overflowing_sub(value);
377
378        registers.p.carry = !borrow;
379        registers.p.zero = difference == 0;
380        registers.p.negative = difference.sign_bit();
381    })
382);

AND: Bitwise and (8-bit)

385impl_read_op_u8!(
386    [
387        immediate -> and_immediate_u8,
388        direct_page -> and_direct_page_u8,
389        direct_page_x -> and_direct_page_x_u8,
390        direct_page_indirect -> and_direct_page_indirect_u8,
391        direct_page_indexed_indirect -> and_direct_page_indexed_indirect_u8,
392        direct_page_indirect_indexed -> and_direct_page_indirect_indexed_u8,
393        direct_page_indirect_long -> and_direct_page_indirect_long_u8,
394        direct_page_indirect_long_indexed -> and_direct_page_indirect_long_indexed_u8,
395        absolute -> and_absolute_u8,
396        absolute_x -> and_absolute_x_u8,
397        absolute_y -> and_absolute_y_u8,
398        absolute_long -> and_absolute_long_u8,
399        absolute_long_x -> and_absolute_long_x_u8,
400        stack_relative -> and_stack_relative_u8,
401        stack_relative_indirect_indexed -> and_stack_relative_indirect_indexed_u8,
402    ]
403    (|registers, value| {
404        let result = (registers.a as u8) & value;
405        registers.a.set_lsb(result);
406
407        registers.p.zero = result == 0;
408        registers.p.negative = result.sign_bit();
409    })
410);

AND: Bitwise and (16-bit)

413impl_read_op_u16!(
414    [
415        immediate -> and_immediate_u16,
416        direct_page -> and_direct_page_u16,
417        direct_page_x -> and_direct_page_x_u16,
418        direct_page_indirect -> and_direct_page_indirect_u16,
419        direct_page_indexed_indirect -> and_direct_page_indexed_indirect_u16,
420        direct_page_indirect_indexed -> and_direct_page_indirect_indexed_u16,
421        direct_page_indirect_long -> and_direct_page_indirect_long_u16,
422        direct_page_indirect_long_indexed -> and_direct_page_indirect_long_indexed_u16,
423        absolute -> and_absolute_u16,
424        absolute_x -> and_absolute_x_u16,
425        absolute_y -> and_absolute_y_u16,
426        absolute_long -> and_absolute_long_u16,
427        absolute_long_x -> and_absolute_long_x_u16,
428        stack_relative -> and_stack_relative_u16,
429        stack_relative_indirect_indexed -> and_stack_relative_indirect_indexed_u16,
430    ]
431    (|registers, value| {
432        let result = registers.a & value;
433        registers.a = result;
434
435        registers.p.zero = result == 0;
436        registers.p.negative = result.sign_bit();
437    })
438);

EOR: Exclusive or (8-bit)

441impl_read_op_u8!(
442    [
443        immediate -> eor_immediate_u8,
444        direct_page -> eor_direct_page_u8,
445        direct_page_x -> eor_direct_page_x_u8,
446        direct_page_indirect -> eor_direct_page_indirect_u8,
447        direct_page_indexed_indirect -> eor_direct_page_indexed_indirect_u8,
448        direct_page_indirect_indexed -> eor_direct_page_indirect_indexed_u8,
449        direct_page_indirect_long -> eor_direct_page_indirect_long_u8,
450        direct_page_indirect_long_indexed -> eor_direct_page_indirect_long_indexed_u8,
451        absolute -> eor_absolute_u8,
452        absolute_x -> eor_absolute_x_u8,
453        absolute_y -> eor_absolute_y_u8,
454        absolute_long -> eor_absolute_long_u8,
455        absolute_long_x -> eor_absolute_long_x_u8,
456        stack_relative -> eor_stack_relative_u8,
457        stack_relative_indirect_indexed -> eor_stack_relative_indirect_indexed_u8,
458    ]
459    (|registers, value| {
460        let result = (registers.a as u8) ^ value;
461        registers.a.set_lsb(result);
462
463        registers.p.zero = result == 0;
464        registers.p.negative = result.sign_bit();
465    })
466);

EOR: Exclusive or (16-bit)

469impl_read_op_u16!(
470    [
471        immediate -> eor_immediate_u16,
472        direct_page -> eor_direct_page_u16,
473        direct_page_x -> eor_direct_page_x_u16,
474        direct_page_indirect -> eor_direct_page_indirect_u16,
475        direct_page_indexed_indirect -> eor_direct_page_indexed_indirect_u16,
476        direct_page_indirect_indexed -> eor_direct_page_indirect_indexed_u16,
477        direct_page_indirect_long -> eor_direct_page_indirect_long_u16,
478        direct_page_indirect_long_indexed -> eor_direct_page_indirect_long_indexed_u16,
479        absolute -> eor_absolute_u16,
480        absolute_x -> eor_absolute_x_u16,
481        absolute_y -> eor_absolute_y_u16,
482        absolute_long -> eor_absolute_long_u16,
483        absolute_long_x -> eor_absolute_long_x_u16,
484        stack_relative -> eor_stack_relative_u16,
485        stack_relative_indirect_indexed -> eor_stack_relative_indirect_indexed_u16,
486    ]
487    (|registers, value| {
488        let result = registers.a ^ value;
489        registers.a = result;
490
491        registers.p.zero = result == 0;
492        registers.p.negative = result.sign_bit();
493    })
494);

ORA: Bitwise or with accumulator (8-bit)

497impl_read_op_u8!(
498    [
499        immediate -> ora_immediate_u8,
500        direct_page -> ora_direct_page_u8,
501        direct_page_x -> ora_direct_page_x_u8,
502        direct_page_indirect -> ora_direct_page_indirect_u8,
503        direct_page_indexed_indirect -> ora_direct_page_indexed_indirect_u8,
504        direct_page_indirect_indexed -> ora_direct_page_indirect_indexed_u8,
505        direct_page_indirect_long -> ora_direct_page_indirect_long_u8,
506        direct_page_indirect_long_indexed -> ora_direct_page_indirect_long_indexed_u8,
507        absolute -> ora_absolute_u8,
508        absolute_x -> ora_absolute_x_u8,
509        absolute_y -> ora_absolute_y_u8,
510        absolute_long -> ora_absolute_long_u8,
511        absolute_long_x -> ora_absolute_long_x_u8,
512        stack_relative -> ora_stack_relative_u8,
513        stack_relative_indirect_indexed -> ora_stack_relative_indirect_indexed_u8,
514    ]
515    (|registers, value| {
516        let result = (registers.a as u8) | value;
517        registers.a.set_lsb(result);
518
519        registers.p.zero = result == 0;
520        registers.p.negative = result.sign_bit();
521    })
522);

ORA: Bitwise or with accumulator (16-bit)

525impl_read_op_u16!(
526    [
527        immediate -> ora_immediate_u16,
528        direct_page -> ora_direct_page_u16,
529        direct_page_x -> ora_direct_page_x_u16,
530        direct_page_indirect -> ora_direct_page_indirect_u16,
531        direct_page_indexed_indirect -> ora_direct_page_indexed_indirect_u16,
532        direct_page_indirect_indexed -> ora_direct_page_indirect_indexed_u16,
533        direct_page_indirect_long -> ora_direct_page_indirect_long_u16,
534        direct_page_indirect_long_indexed -> ora_direct_page_indirect_long_indexed_u16,
535        absolute -> ora_absolute_u16,
536        absolute_x -> ora_absolute_x_u16,
537        absolute_y -> ora_absolute_y_u16,
538        absolute_long -> ora_absolute_long_u16,
539        absolute_long_x -> ora_absolute_long_x_u16,
540        stack_relative -> ora_stack_relative_u16,
541        stack_relative_indirect_indexed -> ora_stack_relative_indirect_indexed_u16,
542    ]
543    (|registers, value| {
544        let result = registers.a | value;
545        registers.a = result;
546
547        registers.p.zero = result == 0;
548        registers.p.negative = result.sign_bit();
549    })
550);
552macro_rules! impl_increment {
553    ($registers:expr, $value:expr, $inc_method:ident) => {{
554        let result = $value.$inc_method(1);
555        $registers.p.zero = result == 0;
556        $registers.p.negative = result.sign_bit();
557
558        result
559    }};
560}

INC: Increment (8-bit)

563impl_modify_op_u8!(
564    [
565        accumulator -> inc_accumulator_u8,
566        direct_page -> inc_direct_page_u8,
567        direct_page_x -> inc_direct_page_x_u8,
568        absolute -> inc_absolute_u8,
569        absolute_x -> inc_absolute_x_u8,
570    ]
571    (|registers, value| {
572        impl_increment!(registers, value, wrapping_add)
573    })
574);

INC: Increment (16-bit)

577impl_modify_op_u16!(
578    [
579        accumulator -> inc_accumulator_u16,
580        direct_page -> inc_direct_page_u16,
581        direct_page_x -> inc_direct_page_x_u16,
582        absolute -> inc_absolute_u16,
583        absolute_x -> inc_absolute_x_u16,
584    ]
585    (|registers, value| {
586        impl_increment!(registers, value, wrapping_add)
587    })
588);

DEC: Decrement (8-bit)

591impl_modify_op_u8!(
592    [
593        accumulator -> dec_accumulator_u8,
594        direct_page -> dec_direct_page_u8,
595        direct_page_x -> dec_direct_page_x_u8,
596        absolute -> dec_absolute_u8,
597        absolute_x -> dec_absolute_x_u8,
598    ]
599    (|registers, value| {
600        impl_increment!(registers, value, wrapping_sub)
601    })
602);

DEC: Decrement (16-bit)

605impl_modify_op_u16!(
606    [
607        accumulator -> dec_accumulator_u16,
608        direct_page -> dec_direct_page_u16,
609        direct_page_x -> dec_direct_page_x_u16,
610        absolute -> dec_absolute_u16,
611        absolute_x -> dec_absolute_x_u16,
612    ]
613    (|registers, value| {
614        impl_increment!(registers, value, wrapping_sub)
615    })
616);

INX: Increment X register

619impl_registers_op!(inx_u8, |registers| {
620    let result = impl_increment!(registers, registers.x as u8, wrapping_add);
621    registers.x = result.into();
622});
623impl_registers_op!(inx_u16, |registers| {
624    let result = impl_increment!(registers, registers.x, wrapping_add);
625    registers.x = result;
626});

INY: Increment Y register

629impl_registers_op!(iny_u8, |registers| {
630    let result = impl_increment!(registers, registers.y as u8, wrapping_add);
631    registers.y = result.into();
632});
633impl_registers_op!(iny_u16, |registers| {
634    let result = impl_increment!(registers, registers.y, wrapping_add);
635    registers.y = result;
636});

DEX: Decrement X register

639impl_registers_op!(dex_u8, |registers| {
640    let result = impl_increment!(registers, registers.x as u8, wrapping_sub);
641    registers.x = result.into();
642});
643impl_registers_op!(dex_u16, |registers| {
644    let result = impl_increment!(registers, registers.x, wrapping_sub);
645    registers.x = result;
646});

DEY: Decrement Y register

649impl_registers_op!(dey_u8, |registers| {
650    let result = impl_increment!(registers, registers.y as u8, wrapping_sub);
651    registers.y = result.into();
652});
653impl_registers_op!(dey_u16, |registers| {
654    let result = impl_increment!(registers, registers.y, wrapping_sub);
655    registers.y = result;
656});