jevsnes.git / third-party / rust / jgenesis / cpu / spc700-emu / src / instructions.rs
1mod alu;
2mod bits;
3mod disassemble;
4mod flags;
5mod flow;
6mod load;
7
8use crate::Spc700;
9use crate::traits::BusInterface;
10use jgenesis_common::num::{GetBit, SignBit};
11
12fn fetch_operand<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) -> u8 {
13    let operand = bus.read(cpu.registers.pc);
14    cpu.registers.pc = cpu.registers.pc.wrapping_add(1);
15
16    log::trace!("Fetched operand from PC={:04X}: {operand:02X}", cpu.registers.pc.wrapping_sub(1));
17
18    operand
19}
20
21macro_rules! invalid_cycle {
22    ($cpu:expr) => {
23        panic!("Invalid cycle for opcode {:02X}: {}", $cpu.state.opcode, $cpu.state.cycle)
24    };
25}
26
27use invalid_cycle;
28
29macro_rules! impl_read_immediate {
30    ($name:ident, (|$registers:ident, $value:ident| $body:block)) => {
31        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
32            cpu.final_cycle();
33
34            let $value = fetch_operand(cpu, bus);
35            let $registers = &mut cpu.registers;
36            $body
37        }
38    };
39}
40
41use impl_read_immediate;
42
43macro_rules! impl_read_register_indirect {
44    ($index:ident, $name:ident, (|$registers:ident, $value:ident| $body:block)) => {
45        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
46            match cpu.state.cycle {
47                1 => {
48                    bus.idle();
49                }
50                2 => {
51                    cpu.final_cycle();
52
53                    let address = u16::from_le_bytes([cpu.registers.$index, cpu.direct_page_msb()]);
54                    let $value = bus.read(address);
55                    let $registers = &mut cpu.registers;
56                    $body
57                }
58                _ => invalid_cycle!(cpu),
59            }
60        }
61    };
62}
63
64use impl_read_register_indirect;
65
66macro_rules! impl_read_register_indirect_postinc {
67    ($index:ident, $name:ident, (|$registers:ident, $value:ident| $body:block)) => {
68        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
69            match cpu.state.cycle {
70                1 => {
71                    bus.idle();
72                }
73                2 => {
74                    let address = u16::from_le_bytes([cpu.registers.$index, cpu.direct_page_msb()]);
75                    let $value = bus.read(address);
76                    let $registers = &mut cpu.registers;
77                    $body
78                }
79                3 => {
80                    cpu.final_cycle();
81
82                    bus.idle();
83                    cpu.registers.$index = cpu.registers.$index.wrapping_add(1);
84                }
85                _ => invalid_cycle!(cpu),
86            }
87        }
88    };
89}
90
91use impl_read_register_indirect_postinc;
92
93macro_rules! impl_read_direct_page {
94    ($name:ident, (|$registers:ident, $value:ident| $body:block)) => {
95        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
96            match cpu.state.cycle {
97                1 => {
98                    cpu.state.t0 = fetch_operand(cpu, bus);
99                }
100                2 => {
101                    cpu.final_cycle();
102
103                    let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]);
104                    let $value = bus.read(address);
105                    let $registers = &mut cpu.registers;
106                    $body
107                }
108                _ => invalid_cycle!(cpu),
109            }
110        }
111    };
112}
113
114use impl_read_direct_page;
115
116macro_rules! impl_read_direct_page_indexed {
117    ($index:ident, $name:ident, (|$registers:ident, $value:ident| $body:block)) => {
118        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
119            match cpu.state.cycle {
120                1 => {
121                    cpu.state.t0 = fetch_operand(cpu, bus);
122                }
123                2 => {
124                    bus.idle();
125                }
126                3 => {
127                    cpu.final_cycle();
128
129                    let address_lsb = cpu.state.t0.wrapping_add(cpu.registers.$index);
130                    let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]);
131                    let $value = bus.read(address);
132                    let $registers = &mut cpu.registers;
133                    $body
134                }
135                _ => invalid_cycle!(cpu),
136            }
137        }
138    };
139}
140
141use impl_read_direct_page_indexed;
142
143macro_rules! impl_read_absolute {
144    ($name:ident, (|$registers:ident, $value:ident| $body:block)) => {
145        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
146            match cpu.state.cycle {
147                1 => {
148                    cpu.state.t0 = fetch_operand(cpu, bus);
149                }
150                2 => {
151                    cpu.state.t1 = fetch_operand(cpu, bus);
152                }
153                3 => {
154                    cpu.final_cycle();
155
156                    let address = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]);
157                    let $value = bus.read(address);
158                    let $registers = &mut cpu.registers;
159                    $body
160                }
161                _ => invalid_cycle!(cpu),
162            }
163        }
164    };
165}
166
167use impl_read_absolute;
168
169macro_rules! impl_read_absolute_indexed {
170    ($index:ident, $name:ident, (|$registers:ident, $value:ident| $body:block)) => {
171        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
172            match cpu.state.cycle {
173                1 => {
174                    cpu.state.t0 = fetch_operand(cpu, bus);
175                }
176                2 => {
177                    cpu.state.t1 = fetch_operand(cpu, bus);
178                }
179                3 => {
180                    bus.idle();
181                }
182                4 => {
183                    cpu.final_cycle();
184
185                    let address = u16::from_le_bytes([cpu.state.t0, cpu.state.t1])
186                        .wrapping_add(cpu.registers.$index.into());
187                    let $value = bus.read(address);
188                    let $registers = &mut cpu.registers;
189                    $body
190                }
191                _ => invalid_cycle!(cpu),
192            }
193        }
194    };
195}
196
197use impl_read_absolute_indexed;
198
199macro_rules! impl_read_indexed_indirect {
200    ($name:ident, (|$registers:ident, $value:ident| $body:block)) => {
201        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
202            match cpu.state.cycle {
203                1 => {
204                    cpu.state.t0 = fetch_operand(cpu, bus);
205                }
206                2 => {
207                    bus.idle();
208                }
209                3 => {
210                    let address_lsb = cpu.state.t0.wrapping_add(cpu.registers.x);
211                    let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]);
212                    cpu.state.t1 = bus.read(address);
213                }
214                4 => {
215                    let address_lsb = cpu.state.t0.wrapping_add(cpu.registers.x).wrapping_add(1);
216                    let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]);
217                    cpu.state.t2 = bus.read(address);
218                }
219                5 => {
220                    cpu.final_cycle();
221
222                    let address = u16::from_le_bytes([cpu.state.t1, cpu.state.t2]);
223                    let $value = bus.read(address);
224                    let $registers = &mut cpu.registers;
225                    $body
226                }
227                _ => invalid_cycle!(cpu),
228            }
229        }
230    };
231}
232
233use impl_read_indexed_indirect;
234
235macro_rules! impl_read_indirect_indexed {
236    ($name:ident, (|$registers:ident, $value:ident| $body:block)) => {
237        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
238            match cpu.state.cycle {
239                1 => {
240                    cpu.state.t0 = fetch_operand(cpu, bus);
241                }
242                2 => {
243                    bus.idle();
244                }
245                3 => {
246                    let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]);
247                    cpu.state.t1 = bus.read(address);
248                }
249                4 => {
250                    let address_lsb = cpu.state.t0.wrapping_add(1);
251                    let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]);
252                    cpu.state.t2 = bus.read(address);
253                }
254                5 => {
255                    cpu.final_cycle();
256
257                    let address = u16::from_le_bytes([cpu.state.t1, cpu.state.t2])
258                        .wrapping_add(cpu.registers.y.into());
259                    let $value = bus.read(address);
260                    let $registers = &mut cpu.registers;
261                    $body
262                }
263                _ => invalid_cycle!(cpu),
264            }
265        }
266    };
267}
268
269use impl_read_indirect_indexed;
270
271macro_rules! impl_read_op {
272    (@inner immediate, $($rest:tt)*) => {
273        impl_read_immediate!($($rest)*);
274    };
275    (@inner x_indirect, $($rest:tt)*) => {
276        impl_read_register_indirect!(x, $($rest)*);
277    };
278    (@inner x_indirect_postinc, $($rest:tt)*) => {
279        impl_read_register_indirect_postinc!(x, $($rest)*);
280    };
281    (@inner direct_page, $($rest:tt)*) => {
282        impl_read_direct_page!($($rest)*);
283    };
284    (@inner direct_page_x, $($rest:tt)*) => {
285        impl_read_direct_page_indexed!(x, $($rest)*);
286    };
287    (@inner direct_page_y, $($rest:tt)*) => {
288        impl_read_direct_page_indexed!(y, $($rest)*);
289    };
290    (@inner absolute, $($rest:tt)*) => {
291        impl_read_absolute!($($rest)*);
292    };
293    (@inner absolute_x, $($rest:tt)*) => {
294        impl_read_absolute_indexed!(x, $($rest)*);
295    };
296    (@inner absolute_y, $($rest:tt)*) => {
297        impl_read_absolute_indexed!(y, $($rest)*);
298    };
299    (@inner indirect_x, $($rest:tt)*) => {
300        impl_read_indexed_indirect!($($rest)*);
301    };
302    (@inner indirect_y, $($rest:tt)*) => {
303        impl_read_indirect_indexed!($($rest)*);
304    };
305    ([$($am:tt -> $name:ident),* $(,)?] $rest:tt) => {
306        $(
307            impl_read_op!(@inner $am, $name, $rest);
308        )*
309    }
310}
311
312use impl_read_op;
313
314macro_rules! impl_x_y {
315    ($write:expr, $name:ident, (|$registers:ident, $operand_l:ident, $operand_r:ident| $body:block)) => {
316        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
317            match cpu.state.cycle {
318                1 => {
319                    bus.idle();
320                }
321                2 => {
322                    let address = u16::from_le_bytes([cpu.registers.y, cpu.direct_page_msb()]);
323                    cpu.state.t0 = bus.read(address);
324                }
325                3 => {
326                    let address = u16::from_le_bytes([cpu.registers.x, cpu.direct_page_msb()]);
327                    cpu.state.t1 = bus.read(address);
328                }
329                4 => {
330                    cpu.final_cycle();
331
332                    let $operand_l = cpu.state.t1;
333                    let $operand_r = cpu.state.t0;
334                    let $registers = &mut cpu.registers;
335                    let value = $body;
336
337                    if $write {
338                        let address = u16::from_le_bytes([cpu.registers.x, cpu.direct_page_msb()]);
339                        bus.write(address, value);
340                    } else {
341                        bus.idle();
342                    }
343                }
344                _ => invalid_cycle!(cpu),
345            }
346        }
347    };
348}
349
350use impl_x_y;
351
352macro_rules! impl_dp_dp {
353    ($write:expr, $name:ident, (|$registers:ident, $operand_l:ident, $operand_r:ident| $body:block)) => {
354        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
355            match cpu.state.cycle {
356                1 => {
357                    cpu.state.t0 = fetch_operand(cpu, bus);
358                }
359                2 => {
360                    let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]);
361                    cpu.state.t1 = bus.read(address);
362                }
363                3 => {
364                    cpu.state.t2 = fetch_operand(cpu, bus);
365                }
366                4 => {
367                    let address = u16::from_le_bytes([cpu.state.t2, cpu.direct_page_msb()]);
368                    cpu.state.t3 = bus.read(address);
369                }
370                5 => {
371                    cpu.final_cycle();
372
373                    let $operand_l = cpu.state.t3;
374                    let $operand_r = cpu.state.t1;
375                    let $registers = &mut cpu.registers;
376                    let value = $body;
377
378                    if $write {
379                        let address = u16::from_le_bytes([cpu.state.t2, cpu.direct_page_msb()]);
380                        bus.write(address, value);
381                    } else {
382                        bus.idle();
383                    }
384                }
385                _ => invalid_cycle!(cpu),
386            }
387        }
388    };
389}
390
391use impl_dp_dp;
392
393macro_rules! impl_dp_imm {
394    ($write:expr, $name:ident, (|$registers:ident, $operand_l:ident, $operand_r:ident| $body:block)) => {
395        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
396            match cpu.state.cycle {
397                1 => {
398                    cpu.state.t0 = fetch_operand(cpu, bus);
399                }
400                2 => {
401                    cpu.state.t1 = fetch_operand(cpu, bus);
402                }
403                3 => {
404                    let address = u16::from_le_bytes([cpu.state.t1, cpu.direct_page_msb()]);
405                    cpu.state.t2 = bus.read(address);
406                }
407                4 => {
408                    cpu.final_cycle();
409
410                    let $operand_l = cpu.state.t2;
411                    let $operand_r = cpu.state.t0;
412                    let $registers = &mut cpu.registers;
413                    let value = $body;
414
415                    if $write {
416                        let address = u16::from_le_bytes([cpu.state.t1, cpu.direct_page_msb()]);
417                        bus.write(address, value);
418                    } else {
419                        bus.idle();
420                    }
421                }
422                _ => invalid_cycle!(cpu),
423            }
424        }
425    };
426}
427
428use impl_dp_imm;
429
430macro_rules! impl_memory_to_memory_op {
431    (@inner x_y, $($rest:tt)*) => {
432        impl_x_y!(true, $($rest)*);
433    };
434    (@inner x_y_no_write, $($rest:tt)*) => {
435        impl_x_y!(false, $($rest)*);
436    };
437    (@inner dp_dp, $($rest:tt)*) => {
438        impl_dp_dp!(true, $($rest)*);
439    };
440    (@inner dp_dp_no_write, $($rest:tt)*) => {
441        impl_dp_dp!(false, $($rest)*);
442    };
443    (@inner dp_imm, $($rest:tt)*) => {
444        impl_dp_imm!(true, $($rest)*);
445    };
446    (@inner dp_imm_no_write, $($rest:tt)*) => {
447        impl_dp_imm!(false, $($rest)*);
448    };
449    ([$($am:tt -> $name:ident),* $(,)?] $rest:tt) => {
450        $(
451            impl_memory_to_memory_op!(@inner $am, $name, $rest);
452        )*
453    }
454}
455
456use impl_memory_to_memory_op;
457
458macro_rules! impl_modify_accumulator {
459    ($name:ident, (|$registers:ident, $value:ident| $body:block)) => {
460        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
461            cpu.final_cycle();
462            bus.idle();
463
464            let $value = cpu.registers.a;
465            let $registers = &mut cpu.registers;
466            cpu.registers.a = $body;
467        }
468    };
469}
470
471use impl_modify_accumulator;
472
473macro_rules! impl_modify_direct_page {
474    ($name:ident, (|$registers:ident, $value:ident| $body:block)) => {
475        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
476            match cpu.state.cycle {
477                1 => {
478                    cpu.state.t0 = fetch_operand(cpu, bus);
479                }
480                2 => {
481                    let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]);
482                    cpu.state.t1 = bus.read(address);
483                }
484                3 => {
485                    cpu.final_cycle();
486
487                    let $value = cpu.state.t1;
488                    let $registers = &mut cpu.registers;
489                    let value = $body;
490
491                    let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]);
492                    bus.write(address, value);
493                }
494                _ => invalid_cycle!(cpu),
495            }
496        }
497    };
498}
499
500use impl_modify_direct_page;
501
502macro_rules! impl_modify_direct_page_indexed {
503    ($index:ident, $name:ident, (|$registers:ident, $value:ident| $body:block)) => {
504        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
505            match cpu.state.cycle {
506                1 => {
507                    cpu.state.t0 = fetch_operand(cpu, bus);
508                }
509                2 => {
510                    bus.idle();
511                }
512                3 => {
513                    let address_lsb = cpu.state.t0.wrapping_add(cpu.registers.$index);
514                    let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]);
515                    cpu.state.t1 = bus.read(address);
516                }
517                4 => {
518                    cpu.final_cycle();
519
520                    let $value = cpu.state.t1;
521                    let $registers = &mut cpu.registers;
522                    let value = $body;
523
524                    let address_lsb = cpu.state.t0.wrapping_add(cpu.registers.$index);
525                    let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]);
526                    bus.write(address, value);
527                }
528                _ => invalid_cycle!(cpu),
529            }
530        }
531    };
532}
533
534use impl_modify_direct_page_indexed;
535
536macro_rules! impl_modify_absolute {
537    ($name:ident, (|$registers:ident, $value:ident| $body:block)) => {
538        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
539            match cpu.state.cycle {
540                1 => {
541                    cpu.state.t0 = fetch_operand(cpu, bus);
542                }
543                2 => {
544                    cpu.state.t1 = fetch_operand(cpu, bus);
545                }
546                3 => {
547                    let address = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]);
548                    cpu.state.t2 = bus.read(address);
549                }
550                4 => {
551                    cpu.final_cycle();
552
553                    let $value = cpu.state.t2;
554                    let $registers = &mut cpu.registers;
555                    let value = $body;
556
557                    let address = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]);
558                    bus.write(address, value);
559                }
560                _ => invalid_cycle!(cpu),
561            }
562        }
563    };
564}
565
566use impl_modify_absolute;
567
568macro_rules! impl_modify_op {
569    (@inner accumulator, $($rest:tt)*) => {
570        impl_modify_accumulator!($($rest)*);
571    };
572    (@inner direct_page, $($rest:tt)*) => {
573        impl_modify_direct_page!($($rest)*);
574    };
575    (@inner direct_page_x, $($rest:tt)*) => {
576        impl_modify_direct_page_indexed!(x, $($rest)*);
577    };
578    (@inner absolute, $($rest:tt)*) => {
579        impl_modify_absolute!($($rest)*);
580    };
581    ([$($am:tt -> $name:ident),* $(,)?] $rest:tt) => {
582        $(
583            impl_modify_op!(@inner $am, $name, $rest);
584        )*
585    }
586}
587
588use impl_modify_op;
589
590macro_rules! impl_registers_op {
591    ($name:ident, |$registers:ident| $body:block) => {
592        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
593            cpu.final_cycle();
594            bus.idle();
595
596            let $registers = &mut cpu.registers;
597            $body
598        }
599    };
600}
601
602use impl_registers_op;
603
604macro_rules! impl_long_registers_op {
605    ($name:ident, |$registers:ident| $body:block) => {
606        pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
607            match cpu.state.cycle {
608                1 => {
609                    bus.idle();
610                }
611                2 => {
612                    cpu.final_cycle();
613                    bus.idle();
614
615                    let $registers = &mut cpu.registers;
616                    $body
617                }
618                _ => invalid_cycle!(cpu),
619            }
620        }
621    };
622}
623
624use impl_long_registers_op;
625
626impl_registers_op!(nop, |_registers| {});
627
628pub fn execute<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
629    if cpu.state.stopped {
630        bus.idle();
631        return;
632    }
633
634    if cpu.state.cycle != 0 {
635        execute_cycle(cpu, bus);
636
637        if cpu.state.cycle != 0 {
638            cpu.state.cycle += 1;
639        }
640
641        return;
642    }
643
644    // Cycle 0: Fetch operand
645    cpu.state.opcode = fetch_operand(cpu, bus);
646    cpu.state.cycle = 1;
647
648    if log::log_enabled!(log::Level::Trace) {
649        let instr_str = disassemble::instruction_str(cpu.state.opcode);
650        log::trace!(
651            "Fetched opcode from PC={:04X}: {:02X} ({instr_str})",
652            cpu.registers.pc.wrapping_sub(1),
653            cpu.state.opcode
654        );
655    }
656}
657
658macro_rules! opcode_table {
659    (
660        $cpu:expr,
661        $bus:expr,
662        { $($opcode:literal => $($module:ident)?::$op_fn:ident $(($arg:expr))?),* $(,)? }
663    ) => {
664        match $cpu.state.opcode {
665            $(
666                $opcode => $($module::)?$op_fn($cpu, $bus $(, $arg)?),
667            )*
668        }
669    }
670}
671
672fn execute_cycle<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) {
673    opcode_table!(cpu, bus, {
674        0x00 => ::nop,
675        0x01 => flow::tcall(0),
676        0x02 => bits::set1(0),
677        0x03 => flow::bbs(0),
678        0x04 => alu::or_dp,
679        0x05 => alu::or_abs,
680        0x06 => alu::or_xind,
681        0x07 => alu::or_indx,
682        0x08 => alu::or_imm,
683        0x09 => alu::or_dp_dp,
684        0x0A => bits::or1,
685        0x0B => bits::asl_dp,
686        0x0C => bits::asl_abs,
687        0x0D => load::push_psw,
688        0x0E => bits::tset1,
689        0x0F => flow::brk,
690        0x10 => flow::bpl,
691        0x11 => flow::tcall(1),
692        0x12 => bits::clr1(0),
693        0x13 => flow::bbc(0),
694        0x14 => alu::or_dpx,
695        0x15 => alu::or_absx,
696        0x16 => alu::or_absy,
697        0x17 => alu::or_indy,
698        0x18 => alu::or_dp_imm,
699        0x19 => alu::or_x_y_ind,
700        0x1A => alu::decw,
701        0x1B => bits::asl_dpx,
702        0x1C => bits::asl_a,
703        0x1D => alu::dec_x,
704        0x1E => alu::cmp_x_abs,
705        0x1F => flow::jmp_absx_ind,
706        0x20 => flags::clrp,
707        0x21 => flow::tcall(2),
708        0x22 => bits::set1(1),
709        0x23 => flow::bbs(1),
710        0x24 => alu::and_dp,
711        0x25 => alu::and_abs,
712        0x26 => alu::and_xind,
713        0x27 => alu::and_indx,
714        0x28 => alu::and_imm,
715        0x29 => alu::and_dp_dp,
716        0x2A => bits::or1_cpl,
717        0x2B => bits::rol_dp,
718        0x2C => bits::rol_abs,
719        0x2D => load::push_a,
720        0x2E => flow::cbne_dp,
721        0x2F => flow::bra,
722        0x30 => flow::bmi,
723        0x31 => flow::tcall(3),
724        0x32 => bits::clr1(1),
725        0x33 => flow::bbc(1),
726        0x34 => alu::and_dpx,
727        0x35 => alu::and_absx,
728        0x36 => alu::and_absy,
729        0x37 => alu::and_indy,
730        0x38 => alu::and_dp_imm,
731        0x39 => alu::and_x_y_ind,
732        0x3A => alu::incw,
733        0x3B => bits::rol_dpx,
734        0x3C => bits::rol_a,
735        0x3D => alu::inc_x,
736        0x3E => alu::cmp_x_dp,
737        0x3F => flow::call,
738        0x40 => flags::setp,
739        0x41 => flow::tcall(4),
740        0x42 => bits::set1(2),
741        0x43 => flow::bbs(2),
742        0x44 => alu::eor_dp,
743        0x45 => alu::eor_abs,
744        0x46 => alu::eor_xind,
745        0x47 => alu::eor_indx,
746        0x48 => alu::eor_imm,
747        0x49 => alu::eor_dp_dp,
748        0x4A => bits::and1,
749        0x4B => bits::lsr_dp,
750        0x4C => bits::lsr_abs,
751        0x4D => load::push_x,
752        0x4E => bits::tclr1,
753        0x4F => flow::pcall,
754        0x50 => flow::bvc,
755        0x51 => flow::tcall(5),
756        0x52 => bits::clr1(2),
757        0x53 => flow::bbc(2),
758        0x54 => alu::eor_dpx,
759        0x55 => alu::eor_absx,
760        0x56 => alu::eor_absy,
761        0x57 => alu::eor_indy,
762        0x58 => alu::eor_dp_imm,
763        0x59 => alu::eor_x_y_ind,
764        0x5A => alu::cmpw,
765        0x5B => bits::lsr_dpx,
766        0x5C => bits::lsr_a,
767        0x5D => load::mov_x_a,
768        0x5E => alu::cmp_y_abs,
769        0x5F => flow::jmp_abs,
770        0x60 => flags::clrc,
771        0x61 => flow::tcall(6),
772        0x62 => bits::set1(3),
773        0x63 => flow::bbs(3),
774        0x64 => alu::cmp_a_dp,
775        0x65 => alu::cmp_a_abs,
776        0x66 => alu::cmp_a_xind,
777        0x67 => alu::cmp_a_indx,
778        0x68 => alu::cmp_a_imm,
779        0x69 => alu::cmp_dp_dp,
780        0x6A => bits::and1_cpl,
781        0x6B => bits::ror_dp,
782        0x6C => bits::ror_abs,
783        0x6D => load::push_y,
784        0x6E => flow::dbnz_dp,
785        0x6F => flow::ret,
786        0x70 => flow::bvs,
787        0x71 => flow::tcall(7),
788        0x72 => bits::clr1(3),
789        0x73 => flow::bbc(3),
790        0x74 => alu::cmp_a_dpx,
791        0x75 => alu::cmp_a_absx,
792        0x76 => alu::cmp_a_absy,
793        0x77 => alu::cmp_a_indy,
794        0x78 => alu::cmp_dp_imm,
795        0x79 => alu::cmp_x_y_ind,
796        0x7A => alu::addw,
797        0x7B => bits::ror_dpx,
798        0x7C => bits::ror_a,
799        0x7D => load::mov_a_x,
800        0x7E => alu::cmp_y_dp,
801        0x7F => flow::reti,
802        0x80 => flags::setc,
803        0x81 => flow::tcall(8),
804        0x82 => bits::set1(4),
805        0x83 => flow::bbs(4),
806        0x84 => alu::adc_dp,
807        0x85 => alu::adc_abs,
808        0x86 => alu::adc_xind,
809        0x87 => alu::adc_indx,
810        0x88 => alu::adc_imm,
811        0x89 => alu::adc_dp_dp,
812        0x8A => bits::eor1,
813        0x8B => alu::dec_dp,
814        0x8C => alu::dec_abs,
815        0x8D => load::mov_y_imm,
816        0x8E => load::pop_psw,
817        0x8F => load::mov_dp_imm,
818        0x90 => flow::bcc,
819        0x91 => flow::tcall(9),
820        0x92 => bits::clr1(4),
821        0x93 => flow::bbc(4),
822        0x94 => alu::adc_dpx,
823        0x95 => alu::adc_absx,
824        0x96 => alu::adc_absy,
825        0x97 => alu::adc_indy,
826        0x98 => alu::adc_dp_imm,
827        0x99 => alu::adc_x_y_ind,
828        0x9A => alu::subw,
829        0x9B => alu::dec_dpx,
830        0x9C => alu::dec_a,
831        0x9D => load::mov_x_sp,
832        0x9E => alu::div,
833        0x9F => bits::xcn,
834        0xA0 => flags::ei,
835        0xA1 => flow::tcall(10),
836        0xA2 => bits::set1(5),
837        0xA3 => flow::bbs(5),
838        0xA4 => alu::sbc_dp,
839        0xA5 => alu::sbc_abs,
840        0xA6 => alu::sbc_xind,
841        0xA7 => alu::sbc_indx,
842        0xA8 => alu::sbc_imm,
843        0xA9 => alu::sbc_dp_dp,
844        0xAA => bits::mov1_c_bit,
845        0xAB => alu::inc_dp,
846        0xAC => alu::inc_abs,
847        0xAD => alu::cmp_y_imm,
848        0xAE => load::pop_a,
849        0xAF => load::mov_xind_postinc_a,
850        0xB0 => flow::bcs,
851        0xB1 => flow::tcall(11),
852        0xB2 => bits::clr1(5),
853        0xB3 => flow::bbc(5),
854        0xB4 => alu::sbc_dpx,
855        0xB5 => alu::sbc_absx,
856        0xB6 => alu::sbc_absy,
857        0xB7 => alu::sbc_indy,
858        0xB8 => alu::sbc_dp_imm,
859        0xB9 => alu::sbc_x_y_ind,
860        0xBA => load::movw_ya_dp,
861        0xBB => alu::inc_dpx,
862        0xBC => alu::inc_a,
863        0xBD => load::mov_sp_x,
864        0xBE => alu::das,
865        0xBF => load::mov_a_xind_postinc,
866        0xC0 => flags::di,
867        0xC1 => flow::tcall(12),
868        0xC2 => bits::set1(6),
869        0xC3 => flow::bbs(6),
870        0xC4 => load::mov_dp_a,
871        0xC5 => load::mov_abs_a,
872        0xC6 => load::mov_xind_a,
873        0xC7 => load::mov_indx_a,
874        0xC8 => alu::cmp_x_imm,
875        0xC9 => load::mov_abs_x,
876        0xCA => bits::mov1_bit_c,
877        0xCB => load::mov_dp_y,
878        0xCC => load::mov_abs_y,
879        0xCD => load::mov_x_imm,
880        0xCE => load::pop_x,
881        0xCF => alu::mul,
882        0xD0 => flow::bne,
883        0xD1 => flow::tcall(13),
884        0xD2 => bits::clr1(6),
885        0xD3 => flow::bbc(6),
886        0xD4 => load::mov_dpx_a,
887        0xD5 => load::mov_absx_a,
888        0xD6 => load::mov_absy_a,
889        0xD7 => load::mov_indy_a,
890        0xD8 => load::mov_dp_x,
891        0xD9 => load::mov_dpy_x,
892        0xDA => load::movw_dp_ya,
893        0xDB => load::mov_dpx_y,
894        0xDC => alu::dec_y,
895        0xDD => load::mov_a_y,
896        0xDE => flow::cbne_dpx,
897        0xDF => alu::daa,
898        0xE0 => flags::clrv,
899        0xE1 => flow::tcall(14),
900        0xE2 => bits::set1(7),
901        0xE3 => flow::bbs(7),
902        0xE4 => load::mov_a_dp,
903        0xE5 => load::mov_a_abs,
904        0xE6 => load::mov_a_xind,
905        0xE7 => load::mov_a_indx,
906        0xE8 => load::mov_a_imm,
907        0xE9 => load::mov_x_abs,
908        0xEA => bits::not1,
909        0xEB => load::mov_y_dp,
910        0xEC => load::mov_y_abs,
911        0xED => flags::notc,
912        0xEE => load::pop_y,
913        0xEF => flow::stop,
914        0xF0 => flow::beq,
915        0xF1 => flow::tcall(15),
916        0xF2 => bits::clr1(7),
917        0xF3 => flow::bbc(7),
918        0xF4 => load::mov_a_dpx,
919        0xF5 => load::mov_a_absx,
920        0xF6 => load::mov_a_absy,
921        0xF7 => load::mov_a_indy,
922        0xF8 => load::mov_x_dp,
923        0xF9 => load::mov_x_dpy,
924        0xFA => load::mov_dp_dp,
925        0xFB => load::mov_y_dpx,
926        0xFC => alu::inc_y,
927        0xFD => load::mov_y_a,
928        0xFE => flow::dbnz_y,
929        0xFF => flow::stop,
930    });
931}