1use std::{
2 io::{ErrorKind, Write},
3 ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not},
4};
5
6use crate::traits::{Address, InsnWrite};
7
8#[derive(Clone, Debug, Hash, PartialEq, Eq)]
9pub enum W65Address {
10 Absolute(Address),
11 Direct(Address),
12 Long(Address),
13 Rel8(Address),
14 Rel16(Address),
15 IndexedX(Box<W65Address>),
16 IndexedY(Box<W65Address>),
17 Indirect(Box<W65Address>),
18 IndirectLong(Box<W65Address>),
19 Stack { off: i8 },
20}
21
22impl W65Address {
23 pub fn into_addr(self) -> Option<Address> {
24 match self {
25 Self::Stack { .. } => None,
26 Self::Absolute(addr)
27 | Self::Direct(addr)
28 | Self::Long(addr)
29 | Self::Rel8(addr)
30 | Self::Rel16(addr) => Some(addr),
31 Self::IndexedX(addr)
32 | Self::IndexedY(addr)
33 | Self::Indirect(addr)
34 | Self::IndirectLong(addr) => addr.into_addr(),
35 }
36 }
37
38 pub fn is_rel(&self) -> bool {
39 match self {
40 Self::Rel8(_) | Self::Rel16(_) => true,
41 Self::Direct(_) | Self::Absolute(_) | Self::Long(_) | Self::Stack { .. } => false,
42 Self::IndexedX(addr)
43 | Self::IndexedY(addr)
44 | Self::Indirect(addr)
45 | Self::IndirectLong(addr) => addr.is_rel(),
46 }
47 }
48
49 pub fn size(&self) -> usize {
50 match self {
51 Self::Rel8(_) | Self::Direct(_) | Self::Stack { .. } => 1,
52 Self::Absolute(_) | Self::Rel16(_) => 2,
53 Self::Long(_) => 3,
54 Self::IndexedX(addr)
55 | Self::IndexedY(addr)
56 | Self::Indirect(addr)
57 | Self::IndirectLong(addr) => addr.size(),
58 }
59 }
60}
61
62#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
63pub enum W65Register {
64 A,
65 X,
66 Y,
67 D,
68 Dbr,
69 K,
70 S,
71 P,
72}
73
74#[derive(Clone, Debug, Hash, PartialEq, Eq)]
75pub enum W65Operand {
76 Address(W65Address),
77 Immediate(u16),
78 Register(W65Register),
79 RegPair(W65Register, W65Register),
80 Implied,
81 SrcDest { src: Address, dest: Address },
82}
83
84#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
85pub enum W65AddrMode {
86 Imp,
87 Acc,
88 Abs,
89 AbsX,
90 AbsY,
91 Direct,
92 DirectX,
93 DirectY,
94 Long,
95 LongX,
96 Rel8,
97 Rel16,
98 Rel,
99 Indirect,
100 IndirectLong,
101 DirectIndirectLong,
102 DirectIndirectLongY,
103 DirectIndirect,
104 DirectIndirectX,
105 DirectIndirectExX,
106 IndirectX,
107 IndirectExX,
108 DirectIndirectY,
109 IndirectY,
110 Imm8,
111 Imm16,
112 ImmA,
113 ImmX,
114 ImmY,
115 SrcDest,
116 Stack,
117 StackIndirectY,
118 IndX,
119 IndY,
120}
121
122macro_rules! w65_opcodes{
123 {$({$enum:ident, $insn:literal, [$($addr:ident $(| $aux_addr:pat)* => $opcode:literal),* $(,)?] $(,)?}),* $(,)?} => {
124 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
125 pub enum W65Opcode{
126 $($enum),*
127 }
128
129 impl W65Opcode {
130 pub fn from_opcode(opc: u8) -> Option<(W65Opcode,W65AddrMode)>{
131 match opc {
132 $($(#[allow(unreachable_patterns)] $opcode => Some((Self:: $enum, $addr)),)*)*
133 _ => None
134 }
135 }
136
137 pub fn accepts_addr_mode(&self, mode: W65AddrMode) -> bool{
138 match self{
139 $(Self:: $enum => match mode{
140 $($addr $(| $aux_addr)* => true,)*
141 _ => false
142 })*
143 }
144 }
145
146 pub fn is_rel_addr(&self) -> bool{
147 match self{
148 $(Self:: $enum => matches!((W65AddrMode::Rel8,W65AddrMode::Rel16),(W65AddrMode::Imp,W65AddrMode::Imp) $(|($addr $(| $aux_addr)*,_)|(_,$addr $(| $aux_addr)*))*),)*
149 }
150 }
151 pub fn insn(&self) -> &'static str {
152 match self{
153 $(Self:: $enum => $insn),*
154 }
155 }
156
157 pub fn opcode(&self, addr: W65AddrMode) -> Option<u8>{
158 match self{
159 $(Self:: $enum => {
160 match addr{
161 $($addr $(|$aux_addr)* => Some($opcode),)*
162 #[allow(unreachable_patterns)] _ => None
163 }
164 }),*
165 }
166 }
167
168 pub fn immediate_size(&self) -> Option<W65AddrMode>{
169 match self{
170 $(Self:: $enum => {
171 match W65AddrMode::ImmA{
172 $($addr $(|$aux_addr)* => return Some(W65AddrMode::ImmA),)*
173 #[allow(unreachable_patterns)] _ => {}
174 }
175 match W65AddrMode::ImmX{
176 $($addr $(|$aux_addr)* => return Some(W65AddrMode::ImmX),)*
177 #[allow(unreachable_patterns)] _ => {}
178 }
179 match W65AddrMode::ImmY{
180 $($addr $(|$aux_addr)* => return Some(W65AddrMode::ImmA),)*
181 #[allow(unreachable_patterns)] _ => {}
182 }
183 match W65AddrMode::Imm8{
184 $($addr $(|$aux_addr)* => return Some(W65AddrMode::Imm8),)*
185 #[allow(unreachable_patterns)] _ => {}
186 }
187 match W65AddrMode::Imm16{
188 $($addr $(|$aux_addr)* => Some(W65AddrMode::Imm16),)*
189 #[allow(unreachable_patterns)] _ => None
190 }
191 })*
192 }
193 }
194 }
195 }
196}
197
198use W65AddrMode::*;
199
200w65_opcodes! {
201 {
202 Adc, "adc", [
203 DirectIndirectX => 0x61,
204 Stack => 0x63,
205 Direct => 0x65,
206 DirectIndirectLong => 0x67,
207 ImmA | Imm8 | Imm16 => 0x69,
208 Abs => 0x6D,
209 Long => 0x6F,
210 DirectIndirectY => 0x71,
211 DirectIndirect => 0x72,
212 StackIndirectY => 0x73,
213 DirectX => 0x75,
214 DirectIndirectLongY => 0x77,
215 AbsY => 0x79,
216 AbsX => 0x7D,
217 LongX => 0x7F
218 ]
219 },
220 {
221 Sbc, "sbc", [
222 DirectIndirectX => 0xE1,
223 Stack => 0xE3,
224 Direct => 0xE5,
225 DirectIndirectLong => 0xE7,
226 ImmA | Imm8 | Imm16 => 0xE9,
227 Abs => 0xED,
228 Long => 0xEF,
229 DirectIndirectY => 0xF1,
230 DirectIndirect => 0xF2,
231 StackIndirectY => 0xF3,
232 DirectX => 0xF5,
233 DirectIndirectLongY => 0xF7,
234 AbsY => 0xF9,
235 AbsX => 0xFD,
236 LongX => 0xFF
237 ]
238 },
239 {
240 Cmp, "cmp", [
241 DirectIndirectX => 0xD1,
242 Stack => 0xD3,
243 Direct => 0xD5,
244 DirectIndirectLong => 0xD7,
245 ImmA | Imm8 | Imm16 => 0xD9,
246 Abs => 0xDD,
247 Long => 0xDF,
248 DirectIndirectY => 0xE1,
249 DirectIndirect => 0xE2,
250 StackIndirectY => 0xE3,
251 DirectX => 0xE5,
252 DirectIndirectLongY => 0xE7,
253 AbsY => 0xE9,
254 AbsX => 0xED,
255 LongX => 0xEF
256 ]
257 },
258 {
259 Cpx, "cpx", [
260 ImmY | Imm8 | Imm16 => 0xE0,
261 Direct => 0xE4,
262 Abs => 0xEC,
263 ]
264 },
265 {
266 Cpy, "cpy", [
267 ImmY | Imm8 | Imm16 => 0xC0,
268 Direct => 0xC4,
269 Abs => 0xCC,
270 ]
271 },
272 {
273 Dec, "dec", [
274 Acc => 0x3A,
275 Direct => 0xC6,
276 Abs => 0xCE,
277 DirectX => 0xD6,
278 AbsX => 0xDE
279 ]
280 },
281 {
282 Inc, "inc", [
283 Acc => 0x1A,
284 Direct => 0xE6,
285 Abs => 0xEE,
286 DirectX => 0xF6,
287 AbsX => 0xFE
288 ]
289 },
290 {
291 Dex, "dex", [
292 Imp => 0xCA
293 ]
294 },
295 {
296 Dey, "dey", [
297 Imp => 0x88
298 ]
299 },
300 {
301 Inx, "dex", [
302 Imp => 0xE8
303 ]
304 },
305 {
306 Iny, "iny", [
307 Imp => 0xC8
308 ]
309 },
310 {
311 And, "and", [
312 DirectIndirectX => 0x21,
313 Stack => 0x23,
314 Direct => 0x25,
315 DirectIndirectLong => 0x27,
316 ImmA | Imm8 | Imm16 => 0x29,
317 Abs => 0x2D,
318 Long => 0x2F,
319 DirectIndirectY => 0x31,
320 DirectIndirect => 0x32,
321 StackIndirectY => 0x33,
322 DirectX => 0x35,
323 DirectIndirectLongY => 0x37,
324 AbsY => 0x39,
325 AbsX => 0x3D,
326 LongX => 0x3F
327 ]
328 },
329 {
330 Eor, "eor", [
331 DirectIndirectX => 0x41,
332 Stack => 0x43,
333 Direct => 0x45,
334 DirectIndirectLong => 0x47,
335 ImmA | Imm8 | Imm16 => 0x49,
336 Abs => 0x4D,
337 Long => 0x4F,
338 DirectIndirectY => 0x51,
339 DirectIndirect => 0x52,
340 StackIndirectY => 0x53,
341 DirectX => 0x55,
342 DirectIndirectLongY => 0x57,
343 AbsY => 0x59,
344 AbsX => 0x5D,
345 LongX => 0x5F
346 ]
347 },
348 {
349 Ora, "ora", [
350 DirectIndirectX => 0x01,
351 Stack => 0x03,
352 Direct => 0x05,
353 DirectIndirectLong => 0x07,
354 ImmA | Imm8 | Imm16 => 0x09,
355 Abs => 0x0D,
356 Long => 0x0F,
357 DirectIndirectY => 0x11,
358 DirectIndirect => 0x12,
359 StackIndirectY => 0x13,
360 DirectX => 0x15,
361 DirectIndirectLongY => 0x17,
362 AbsY => 0x19,
363 AbsX => 0x1D,
364 LongX => 0x1F
365 ]
366 },
367 {
368 Bit, "bit", [
369 Direct => 0x24,
370 Abs => 0x2C,
371 DirectX => 0x34,
372 AbsX => 0x3C,
373 ImmA | Imm8 | Imm16 => 0x89
374 ]
375 },
376 {
377 Trb, "trb", [
378 Direct => 0x14,
379 Abs => 0x1C
380 ]
381 },
382 {
383 Tsb, "tsb", [
384 Direct => 0x04,
385 Abs => 0x0C
386 ]
387 },
388 {
389 Asl, "asl", [
390 Direct => 0x06,
391 Acc => 0x0A,
392 Abs => 0x0E,
393 DirectX => 0x16,
394 AbsX => 0x1E
395 ]
396 },
397 {
398 Lsr, "lsr", [
399 Direct => 0x46,
400 Acc => 0x4A,
401 Abs => 0x4E,
402 DirectX => 0x56,
403 AbsX => 0x5E
404 ]
405 },
406 {
407 Rol, "rol", [
408 Direct => 0x26,
409 Acc => 0x2A,
410 Abs => 0x2E,
411 DirectX => 0x36,
412 AbsX => 0x3E
413 ]
414 },
415 {
416 Ror, "ror", [
417 Direct => 0x66,
418 Acc => 0x6A,
419 Abs => 0x6E,
420 DirectX => 0x76,
421 AbsX => 0x7E
422 ]
423 },
424 {
425 Bcc, "bcc", [
426 Rel8 => 0x90
427 ]
428 },
429 {
430 Bcs, "bcs", [
431 Rel8 => 0xB0
432 ]
433 },
434 {
435 Beq, "beq", [
436 Rel8 => 0xF0
437 ]
438 },
439 {
440 Bmi, "bmi", [
441 Rel8 => 0x30
442 ]
443 },
444 {
445 Bne, "bne", [
446 Rel8 => 0xD0
447 ]
448 },
449 {
450 Bpl, "bpl", [
451 Rel8 => 0x10
452 ]
453 },
454 {
455 Bra, "bra", [
456 Rel8 => 0x80,
457 Rel16 => 0x82,
458 ]
459 },
460 {
461 Brl, "", []
462 },
463 {
464 Bvc, "bvc", [
465 Rel8 => 0x50
466 ]
467 },
468 {
469 Bvs, "bvs", [
470 Rel8 => 0x70
471 ]
472 },
473 {
474 Jmp, "jmp", [
475 Abs => 0x4C,
476 Long => 0x5C,
477 Indirect => 0x6C,
478 IndirectX => 0x7C,
479 IndirectLong => 0xDC
480 ]
481 },
482 {
483 Jsr, "jsr", [
484 Long => 0x22,
485 Abs => 0x20,
486 AbsX => 0xFC
487 ]
488 },
489 {
490 Rtl, "rtl", [
491 Imp => 0x6B
492 ]
493 },
494 {
495 Rts, "rts", [
496 Imp => 0x60
497 ]
498 },
499 {
500 Brk, "brk", [
501 Imm8 => 0x00
502 ]
503 },
504 {
505 Cop, "cop", [
506 Imm8 => 0x02
507 ]
508 },
509 {
510 Rti, "rti", [
511 Imp => 0x40
512 ]
513 },
514 {
515 Clc, "clc", [
516 Imp => 0x18
517 ]
518 },
519 {
520 Cld, "cld", [
521 Imp => 0xD8
522 ]
523 },
524 {
525 Cli, "cli", [
526 Imp => 0x58
527 ]
528 },
529 {
530 Clv, "clv", [
531 Imp => 0xB8
532 ]
533 },
534 {
535 Sec, "sec", [
536 Imp => 0x38
537 ]
538 },
539 {
540 Sed, "sed", [
541 Imp => 0xF8
542 ]
543 },
544 {
545 Sei, "sei", [
546 Imp => 0x78
547 ]
548 },
549 {
550 Rep, "rep", [
551 Imm8 => 0xC2
552 ]
553 },
554 {
555 Sep, "sep", [
556 Imm8 => 0xE2,
557 ]
558 },
559 {
560 Lda, "lda", [
561 DirectIndirectX => 0xA1,
562 Stack => 0xA3,
563 Direct => 0xA5,
564 DirectIndirectLong => 0xA7,
565 ImmA | Imm8 | Imm16 => 0xA9,
566 Abs => 0xAD,
567 Long => 0xAF,
568 DirectIndirectY => 0xB1,
569 DirectIndirect => 0xB2,
570 StackIndirectY => 0xB3,
571 DirectX => 0xB5,
572 DirectIndirectLongY => 0xB7,
573 AbsY => 0xB9,
574 AbsX => 0xBD,
575 LongX => 0xBF
576 ]
577 },
578 {
579 Sta, "sta", [
580 DirectIndirectX => 0x81,
581 Stack => 0x83,
582 Direct => 0x85,
583 DirectIndirectLong => 0x87,
584 Abs => 0x8D,
585 Long => 0x8F,
586 DirectIndirectY => 0x91,
587 DirectIndirect => 0x92,
588 StackIndirectY => 0x93,
589 DirectX => 0x95,
590 DirectIndirectLongY => 0x97,
591 AbsY => 0x99,
592 AbsX => 0x9D,
593 LongX => 0x9F
594 ]
595 },
596 {
597 Ldx, "ldx", [
598 ImmX => 0xA2,
599 Direct => 0xA6,
600 Abs => 0xAE,
601 DirectY => 0xB6,
602 AbsY => 0xBE
603 ]
604 },
605 {
606 Ldy, "ldy", [
607 ImmY => 0xA0,
608 Direct => 0xA4,
609 Abs => 0xAC,
610 DirectX => 0xB4,
611 AbsX => 0xBC
612 ]
613 },
614 {
615 Stx, "stx", [
616 Direct => 0x86,
617 Abs => 0x8E,
618 DirectY => 0x96,
619 AbsY => 0x9E
620 ]
621 },
622 {
623 Sty, "sty", [
624 Direct => 0x84,
625 Abs => 0x8C,
626 DirectX => 0x94,
627 AbsX => 0x9C
628 ]
629 },
630 {
631 Stz, "stz", [
632 Direct => 0x64,
633 DirectX => 0x74,
634 Abs => 0x9C,
635 AbsX => 0x9E,
636 ]
637 },
638 {
639 Mvn, "mvn", [
640 SrcDest => 0x54
641 ]
642 },
643 {
644 Mvp, "mvp", [
645 SrcDest => 0x44
646 ]
647 },
648 {
649 Nop, "nop", [
650 Imp => 0xEA
651 ]
652 },
653 {
654 Wdm, "wdm", [
655 Imm8 => 0x42
656 ]
657 },
658 {
659 Pea, "pea", [
660 Abs => 0xF4,
661 DirectIndirect => 0xD4,
662 Rel16 => 0x62
663 ]
664 },
665 {
666 Ph, "ph", []
667 },
668 {
669 Pha, "pha", [
670 Imp => 0x48
671 ]
672 },
673 {
674 Phx, "phx", [
675 Imp => 0xDA
676 ]
677 },
678 {
679 Phy, "phy", [
680 Imp => 0x5A
681 ]
682 },
683 {
684 Pl, "pl", []
685 },
686 {
687 Pla, "pla", [
688 Imp => 0x68
689 ]
690 },
691 {
692 Plx, "plx", [
693 Imp => 0xFA
694 ]
695 },
696 {
697 Ply, "ply", [
698 Imp => 0x7A
699 ]
700 },
701 {
702 Phb, "phb", [
703 Imp => 0x8B
704 ]
705 },
706 {
707 Phd, "phd", [
708 Imp => 0x0B
709 ]
710 },
711 {
712 Phk, "phk", [
713 Imp => 0x4B
714 ]
715 },
716 {
717 Php, "php", [
718 Imp => 0x08
719 ]
720 },
721 {
722 Plb, "plb", [
723 Imp => 0xAB
724 ]
725 },
726 {
727 Pld, "pld", [
728 Imp => 0x2B
729 ]
730 },
731 {
732 Plp, "plp", [
733 Imp => 0x28
734 ]
735 },
736 {
737 Stp, "stp", [
738 Imp => 0xDB
739 ]
740 },
741 {
742 Wai, "wai", [
743 Imp => 0xCB
744 ]
745 },
746 {
747 Tr, "tr", []
748 },
749 {
750 Tax, "tax", [
751 Imp => 0xAA
752 ]
753 },
754 {
755 Tay, "tay", [
756 Imp => 0xA8
757 ]
758 },
759 {
760 Tsx, "tsx", [
761 Imp => 0xBA
762 ]
763 },
764 {
765 Txa, "txa", [
766 Imp => 0x8A
767 ]
768 },
769 {
770 Txs, "txs", [
771 Imp => 0x9A
772 ]
773 },
774 {
775 Txy, "txy", [
776 Imp => 0x9B
777 ]
778 },
779 {
780 Tya, "tya", [
781 Imp => 0x98
782 ]
783 },
784 {
785 Tyx, "tyx", [
786 Imp => 0xBB
787 ]
788 },
789 {
790 Tad, "Tad", [
791 Imp => 0x5B
792 ]
793 },
794 {
795 Tas, "tas", [
796 Imp => 0x1B
797 ]
798 },
799 {
800 Tda, "tda", [
801 Imp => 0x7B
802 ]
803 },
804 {
805 Tsa, "tsa", [
806 Imp => 0x3B
807 ]
808 },
809 {
810 Xba, "xba", [
811 Imp => 0xEB
812 ]
813 },
814 {
815 Xce, "xce", [
816 Imp => 0xFB
817 ]
818 }
819}
820
821#[derive(Clone, Debug, Hash, PartialEq, Eq)]
822pub struct W65Instruction {
823 mode: Option<W65Mode>,
824 opc: W65Opcode,
825 opr: W65Operand,
826}
827
828macro_rules! implied_instructions{
829 [$($instr:ident),* $(,)?] => {
830 #[allow(non_upper_case_globals)]
831 impl W65Instruction{
832 $(pub const $instr: Self = Self{mode: None, opc: W65Opcode::$instr, opr: W65Operand::Implied};)*
833 }
834 }
835}
836
837implied_instructions![
838 Dex, Dey, Rtl, Rts, Brk, Rti, Clc, Cld, Cli, Clv, Sec, Sed, Sei, Nop, Wdm, Pha, Phx, Phy, Pla,
839 Plx, Ply, Phb, Phd, Phk, Php, Plb, Pld, Plp, Stp, Wai, Tax, Tay, Tsx, Txa, Txs, Txy, Tya, Tyx,
840 Tad, Tas, Tda, Tsa, Xba, Xce,
841];
842
843impl W65Instruction {
844 pub fn new(opc: W65Opcode, opr: W65Operand) -> Self {
845 Self {
846 mode: None,
847 opc,
848 opr,
849 }
850 }
851
852 pub fn new_in_mode(mode: W65Mode, opc: W65Opcode, opr: W65Operand) -> Self {
853 Self {
854 mode: Some(mode),
855 opc,
856 opr,
857 }
858 }
859
860 pub fn addr_mode(&self) -> Option<W65AddrMode> {
861 match &self.opr {
862 W65Operand::Address(addr) => match addr {
863 W65Address::Absolute(_) => Some(W65AddrMode::Abs),
864 W65Address::Direct(_) => Some(W65AddrMode::Direct),
865 W65Address::Long(_) => Some(W65AddrMode::Long),
866 W65Address::Rel8(_) => Some(W65AddrMode::Rel8),
867 W65Address::Rel16(_) => Some(W65AddrMode::Rel8),
868 W65Address::IndexedX(inner) => match &**inner {
869 W65Address::Absolute(_) => Some(W65AddrMode::AbsX),
870 W65Address::Direct(_) => Some(W65AddrMode::DirectX),
871 W65Address::Indirect(addr) => match &**addr {
872 W65Address::Direct(_) => Some(W65AddrMode::DirectIndirectX),
873 W65Address::Absolute(_) => Some(W65AddrMode::IndirectX),
874 _ => None,
875 },
876 _ => None,
877 },
878 W65Address::IndexedY(inner) => match &**inner {
879 W65Address::Absolute(_) => Some(W65AddrMode::AbsY),
880 W65Address::Direct(_) => Some(W65AddrMode::DirectY),
881 W65Address::IndirectLong(inner) => match &**inner {
882 W65Address::Direct(_) => Some(W65AddrMode::DirectIndirectLongY),
883 _ => None,
884 },
885 W65Address::Indirect(addr) => match &**addr {
886 W65Address::Direct(_) => Some(W65AddrMode::DirectIndirectY),
887 W65Address::Absolute(_) => Some(W65AddrMode::IndirectY),
888 W65Address::Stack { .. } => Some(W65AddrMode::StackIndirectY),
889 _ => None,
890 },
891 _ => None,
892 },
893 W65Address::Indirect(inner) => match &**inner {
894 W65Address::Absolute(_) => Some(W65AddrMode::Indirect),
895 W65Address::Direct(_) => Some(W65AddrMode::Direct),
896 W65Address::IndexedX(inner) => match &**inner {
897 W65Address::Absolute(_) => Some(W65AddrMode::IndirectX),
898 W65Address::Direct(_) => Some(W65AddrMode::DirectIndirectX),
899 _ => None,
900 },
901 _ => None,
902 },
903 W65Address::IndirectLong(_) => todo!(),
904 W65Address::Stack { .. } => Some(W65AddrMode::Stack),
905 },
906 W65Operand::Immediate(_) => {
907 if let Some(mode) = self.opc.immediate_size() {
908 Some(mode)
909 } else if self.opc.is_rel_addr() {
910 if self.opc.accepts_addr_mode(W65AddrMode::Rel16) {
911 Some(W65AddrMode::Rel16)
912 } else {
913 Some(W65AddrMode::Rel8)
914 }
915 } else {
916 None
917 }
918 }
919 W65Operand::Implied => Some(W65AddrMode::Imp),
920 W65Operand::SrcDest { .. } => Some(W65AddrMode::SrcDest),
921 W65Operand::Register(W65Register::A) => Some(W65AddrMode::Acc),
922 W65Operand::Register(W65Register::X) => Some(W65AddrMode::IndX),
923 W65Operand::Register(W65Register::Y) => Some(W65AddrMode::IndY),
924 _ => None,
925 }
926 }
927}
928
929macro_rules! w65_synthetic_instructions{
930 ($([$base_opc:pat, $base_operand:pat => $actual_opc:expr, $actual_operand:expr])*) => {
931 impl W65Instruction{
932 pub fn into_real(self) -> Self{
933 let mode = self.mode;
934 match (self.opc,self.opr){
935 $(($base_opc, $base_operand) => Self{opc: $actual_opc, opr: $actual_operand,mode},)*
936 #[allow(unreachable_patterns)] (opc,opr) => Self{opc,opr,mode}
937 }
938 }
939 }
940 }
941}
942
943w65_synthetic_instructions! {
944 [W65Opcode::Lda, W65Operand::Register(W65Register::X) => W65Opcode::Txa, W65Operand::Implied]
945 [W65Opcode::Lda, W65Operand::Register(W65Register::Y) => W65Opcode::Tya, W65Operand::Implied]
946 [W65Opcode::Lda, W65Operand::Register(W65Register::A) => W65Opcode::Nop, W65Operand::Implied]
947 [W65Opcode::Lda, W65Operand::Register(W65Register::S) => W65Opcode::Tsa, W65Operand::Implied]
948 [W65Opcode::Lda, W65Operand::Register(W65Register::D) => W65Opcode::Tda, W65Operand::Implied]
949 [W65Opcode::Ldx, W65Operand::Register(W65Register::A) => W65Opcode::Tax, W65Operand::Implied]
950 [W65Opcode::Ldx, W65Operand::Register(W65Register::Y) => W65Opcode::Tyx, W65Operand::Implied]
951 [W65Opcode::Ldx, W65Operand::Register(W65Register::X) => W65Opcode::Nop, W65Operand::Implied]
952 [W65Opcode::Ldx, W65Operand::Register(W65Register::S) => W65Opcode::Tsx, W65Operand::Implied]
953 [W65Opcode::Ldy, W65Operand::Register(W65Register::A) => W65Opcode::Tay, W65Operand::Implied]
954 [W65Opcode::Ldy, W65Operand::Register(W65Register::X) => W65Opcode::Txy, W65Operand::Implied]
955 [W65Opcode::Ldy, W65Operand::Register(W65Register::Y) => W65Opcode::Nop, W65Operand::Implied]
956 [W65Opcode::Tr, W65Operand::RegPair(W65Register::A,W65Register::X) => W65Opcode::Txa, W65Operand::Implied]
957 [W65Opcode::Tr, W65Operand::RegPair(W65Register::A,W65Register::Y) => W65Opcode::Tya, W65Operand::Implied]
958 [W65Opcode::Tr, W65Operand::RegPair(W65Register::A,W65Register::A) => W65Opcode::Nop, W65Operand::Implied]
959 [W65Opcode::Tr, W65Operand::RegPair(W65Register::A,W65Register::S) => W65Opcode::Tsa, W65Operand::Implied]
960 [W65Opcode::Tr, W65Operand::RegPair(W65Register::A,W65Register::D) => W65Opcode::Tda, W65Operand::Implied]
961 [W65Opcode::Tr, W65Operand::RegPair(W65Register::X,W65Register::A) => W65Opcode::Tax, W65Operand::Implied]
962 [W65Opcode::Tr, W65Operand::RegPair(W65Register::X,W65Register::Y) => W65Opcode::Tyx, W65Operand::Implied]
963 [W65Opcode::Tr, W65Operand::RegPair(W65Register::X,W65Register::X) => W65Opcode::Nop, W65Operand::Implied]
964 [W65Opcode::Tr, W65Operand::RegPair(W65Register::X,W65Register::S) => W65Opcode::Tsx, W65Operand::Implied]
965 [W65Opcode::Tr, W65Operand::RegPair(W65Register::Y,W65Register::A) => W65Opcode::Tay, W65Operand::Implied]
966 [W65Opcode::Tr, W65Operand::RegPair(W65Register::Y,W65Register::X) => W65Opcode::Txy, W65Operand::Implied]
967 [W65Opcode::Tr, W65Operand::RegPair(W65Register::Y,W65Register::Y) => W65Opcode::Nop, W65Operand::Implied]
968 [W65Opcode::Sta, W65Operand::Register(W65Register::X) => W65Opcode::Tax, W65Operand::Implied]
969 [W65Opcode::Sta, W65Operand::Register(W65Register::Y) => W65Opcode::Tay, W65Operand::Implied]
970 [W65Opcode::Sta, W65Operand::Register(W65Register::A) => W65Opcode::Nop, W65Operand::Implied]
971 [W65Opcode::Sta, W65Operand::Register(W65Register::S) => W65Opcode::Tas, W65Operand::Implied]
972 [W65Opcode::Sta, W65Operand::Register(W65Register::D) => W65Opcode::Tad, W65Operand::Implied]
973 [W65Opcode::Stx, W65Operand::Register(W65Register::A) => W65Opcode::Txa, W65Operand::Implied]
974 [W65Opcode::Stx, W65Operand::Register(W65Register::Y) => W65Opcode::Txy, W65Operand::Implied]
975 [W65Opcode::Stx, W65Operand::Register(W65Register::X) => W65Opcode::Nop, W65Operand::Implied]
976 [W65Opcode::Stx, W65Operand::Register(W65Register::S) => W65Opcode::Txs, W65Operand::Implied]
977 [W65Opcode::Sty, W65Operand::Register(W65Register::A) => W65Opcode::Tya, W65Operand::Implied]
978 [W65Opcode::Sty, W65Operand::Register(W65Register::X) => W65Opcode::Tyx, W65Operand::Implied]
979 [W65Opcode::Sty, W65Operand::Register(W65Register::Y) => W65Opcode::Nop, W65Operand::Implied]
980 [W65Opcode::Tr, W65Operand::RegPair(W65Register::S,W65Register::A) => W65Opcode::Tsa, W65Operand::Implied]
981 [W65Opcode::Tr, W65Operand::RegPair(W65Register::D, W65Register::A) => W65Opcode::Tda, W65Operand::Implied]
982 [W65Opcode::Tr, W65Operand::RegPair(W65Register::S, W65Register::S) => W65Opcode::Tsx, W65Operand::Implied]
983 [W65Opcode::Brk, W65Operand::Implied => W65Opcode::Brk, W65Operand::Immediate(0)]
984 [W65Opcode::Brl, W65Operand::Address(addr) => W65Opcode::Bra, W65Operand::Address(addr)]
985 [W65Opcode::Wdm, W65Operand::Implied => W65Opcode::Wdm, W65Operand::Immediate(0)]
986 [W65Opcode::Ph, W65Operand::Register(W65Register::A) => W65Opcode::Pha, W65Operand::Implied]
987 [W65Opcode::Ph, W65Operand::Register(W65Register::X) => W65Opcode::Phx, W65Operand::Implied]
988 [W65Opcode::Ph, W65Operand::Register(W65Register::Y) => W65Opcode::Phy, W65Operand::Implied]
989 [W65Opcode::Ph, W65Operand::Register(W65Register::D) => W65Opcode::Phd, W65Operand::Implied]
990 [W65Opcode::Ph, W65Operand::Register(W65Register::Dbr) => W65Opcode::Phb, W65Operand::Implied]
991 [W65Opcode::Ph, W65Operand::Register(W65Register::K) => W65Opcode::Phk, W65Operand::Implied]
992 [W65Opcode::Ph, W65Operand::Register(W65Register::P) => W65Opcode::Php, W65Operand::Implied]
993 [W65Opcode::Pl, W65Operand::Register(W65Register::A) => W65Opcode::Pla, W65Operand::Implied]
994 [W65Opcode::Pl, W65Operand::Register(W65Register::X) => W65Opcode::Plx, W65Operand::Implied]
995 [W65Opcode::Pl, W65Operand::Register(W65Register::Y) => W65Opcode::Ply, W65Operand::Implied]
996 [W65Opcode::Pl, W65Operand::Register(W65Register::D) => W65Opcode::Pld, W65Operand::Implied]
997 [W65Opcode::Pl, W65Operand::Register(W65Register::Dbr) => W65Opcode::Plb, W65Operand::Implied]
998 [W65Opcode::Pl, W65Operand::Register(W65Register::P) => W65Opcode::Plp, W65Operand::Implied]
999}
1000
1001#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Default)]
1002pub struct W65Mode {
1003 bits: u16,
1004}
1005
1006impl W65Mode {
1007 pub const NONE: W65Mode = W65Mode { bits: 0 };
1008 pub const M: W65Mode = W65Mode { bits: 0x10 };
1009 pub const X: W65Mode = W65Mode { bits: 0x20 };
1010 pub const E: W65Mode = W65Mode { bits: 0x100 };
1011
1012 pub fn is_acc16(self) -> bool {
1013 !self.is_emu() && ((self.bits & 1) == 0)
1014 }
1015
1016 pub fn is_idx16(self) -> bool {
1017 !self.is_emu() && ((self.bits & 2) == 0)
1018 }
1019
1020 pub fn is_emu(self) -> bool {
1021 self.bits & 4 != 0
1022 }
1023
1024 pub fn get_immediate_size(self, imm: W65AddrMode) -> Option<usize> {
1025 match imm {
1026 W65AddrMode::Imm8 => Some(1),
1027 W65AddrMode::Imm16 => Some(2),
1028 W65AddrMode::ImmA => Some(1 + (self.is_acc16() as usize)),
1029 W65AddrMode::ImmX | W65AddrMode::ImmY => Some(1 + (self.is_idx16() as usize)),
1030 _ => None,
1031 }
1032 }
1033
1034 pub const fn bits(&self) -> u16 {
1035 self.bits
1036 }
1037}
1038
1039impl Not for W65Mode {
1040 type Output = Self;
1041 fn not(self) -> Self {
1042 Self {
1043 bits: (!self.bits) & 0x7,
1044 }
1045 }
1046}
1047
1048impl BitOrAssign for W65Mode {
1049 fn bitor_assign(&mut self, rhs: Self) {
1050 *self = *self | rhs;
1051 }
1052}
1053
1054impl BitAndAssign for W65Mode {
1055 fn bitand_assign(&mut self, rhs: Self) {
1056 *self = *self & rhs;
1057 }
1058}
1059
1060impl BitXorAssign for W65Mode {
1061 fn bitxor_assign(&mut self, rhs: Self) {
1062 *self = *self ^ rhs;
1063 }
1064}
1065
1066impl BitOr for W65Mode {
1067 type Output = Self;
1068 fn bitor(self, rhs: Self) -> Self {
1069 Self {
1070 bits: self.bits | rhs.bits,
1071 }
1072 }
1073}
1074
1075impl BitAnd for W65Mode {
1076 type Output = Self;
1077 fn bitand(self, rhs: Self) -> Self {
1078 Self {
1079 bits: self.bits & rhs.bits,
1080 }
1081 }
1082}
1083
1084impl BitXor for W65Mode {
1085 type Output = Self;
1086 fn bitxor(self, rhs: Self) -> Self {
1087 Self {
1088 bits: self.bits ^ rhs.bits,
1089 }
1090 }
1091}
1092
1093pub struct W65Encoder<W> {
1094 inner: W,
1095 mode: W65Mode,
1096}
1097
1098impl<W> W65Encoder<W> {
1099 pub const fn new(inner: W) -> Self {
1100 Self {
1101 inner,
1102 mode: W65Mode::NONE,
1103 }
1104 }
1105
1106 pub fn into_inner(self) -> W {
1107 self.inner
1108 }
1109
1110 pub const fn writer(&self) -> &W {
1111 &self.inner
1112 }
1113
1114 pub fn writer_mut(&mut self) -> &mut W {
1115 &mut self.inner
1116 }
1117
1118 pub fn set_mode_flags(&mut self, mode: W65Mode) {
1119 self.mode |= mode;
1120 }
1121
1122 pub fn clear_mode_flags(&mut self, mode: W65Mode) {
1123 self.mode &= !mode;
1124 }
1125
1126 pub fn mode(&self) -> W65Mode {
1127 self.mode
1128 }
1129
1130 pub fn mode_mut(&mut self) -> &mut W65Mode {
1131 &mut self.mode
1132 }
1133}
1134
1135impl<W: Write> Write for W65Encoder<W> {
1136 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
1137 self.inner.write(buf)
1138 }
1139
1140 fn flush(&mut self) -> std::io::Result<()> {
1141 self.inner.flush()
1142 }
1143}
1144
1145impl<W: InsnWrite> InsnWrite for W65Encoder<W> {
1146 fn write_addr(&mut self, size: usize, addr: Address, rel: bool) -> std::io::Result<()> {
1147 self.inner.write_addr(size, addr, rel)
1148 }
1149
1150 fn write_reloc(&mut self, reloc: crate::traits::Reloc) -> std::io::Result<()> {
1151 self.inner.write_reloc(reloc)
1152 }
1153
1154 fn offset(&self) -> usize {
1155 self.inner.offset()
1156 }
1157}
1158
1159impl<W: InsnWrite> W65Encoder<W> {
1160 pub fn write_insn(&mut self, insn: W65Instruction) -> std::io::Result<()> {
1161 let mode = insn.mode.unwrap_or(self.mode);
1162 let insn = insn.into_real();
1163 let addr_mode = insn.addr_mode().unwrap();
1164 let opc = insn.opc.opcode(addr_mode).ok_or_else(|| {
1165 std::io::Error::new(
1166 ErrorKind::InvalidInput,
1167 format!(
1168 "Error: Cannot encode {} in mode {:?}",
1169 insn.opc.insn(),
1170 addr_mode
1171 ),
1172 )
1173 })?;
1174
1175 self.write_all(core::slice::from_ref(&opc))?;
1176 match insn.opr {
1177 W65Operand::SrcDest { .. } => {
1178 todo!("src, dest")
1179 }
1180 W65Operand::Immediate(imm) => {
1181 let size = mode.get_immediate_size(addr_mode).unwrap();
1182 self.write_all(&imm.to_le_bytes()[..size])
1183 }
1184 W65Operand::Address(addr) => {
1185 if let W65Address::Stack { off } = &addr {
1186 self.write_all(core::slice::from_ref(&(*off as u8)))
1187 } else {
1188 let size = addr.size();
1189 let rel = addr.is_rel();
1190 self.write_addr(8 * size, addr.into_addr().unwrap(), rel)
1191 }
1192 }
1193 _ => Ok(()),
1194 }
1195 }
1196}