arch_ops/
w65.rs

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}