retroshield_z80_workbench/
instructions.rs

1//! Z80 instruction helpers
2//!
3//! Provides ergonomic methods for emitting Z80 instructions.
4//! Instead of `emit(&[0x3E, 0x0A])` you can write `ld_a(0x0A)`.
5
6use crate::CodeGen;
7
8impl CodeGen {
9    // ========== 8-bit Load Instructions ==========
10
11    /// LD A, n
12    pub fn ld_a(&mut self, n: u8) {
13        self.emit(&[0x3E, n]);
14    }
15
16    /// LD B, n
17    pub fn ld_b(&mut self, n: u8) {
18        self.emit(&[0x06, n]);
19    }
20
21    /// LD C, n
22    pub fn ld_c(&mut self, n: u8) {
23        self.emit(&[0x0E, n]);
24    }
25
26    /// LD D, n
27    pub fn ld_d(&mut self, n: u8) {
28        self.emit(&[0x16, n]);
29    }
30
31    /// LD E, n
32    pub fn ld_e(&mut self, n: u8) {
33        self.emit(&[0x1E, n]);
34    }
35
36    /// LD H, n
37    pub fn ld_h(&mut self, n: u8) {
38        self.emit(&[0x26, n]);
39    }
40
41    /// LD L, n
42    pub fn ld_l(&mut self, n: u8) {
43        self.emit(&[0x2E, n]);
44    }
45
46    /// LD A, (HL)
47    pub fn ld_a_hl_ind(&mut self) {
48        self.emit(&[0x7E]);
49    }
50
51    /// LD (HL), A
52    pub fn ld_hl_ind_a(&mut self) {
53        self.emit(&[0x77]);
54    }
55
56    /// LD A, B
57    pub fn ld_a_b(&mut self) {
58        self.emit(&[0x78]);
59    }
60
61    /// LD A, C
62    pub fn ld_a_c(&mut self) {
63        self.emit(&[0x79]);
64    }
65
66    /// LD A, D
67    pub fn ld_a_d(&mut self) {
68        self.emit(&[0x7A]);
69    }
70
71    /// LD A, E
72    pub fn ld_a_e(&mut self) {
73        self.emit(&[0x7B]);
74    }
75
76    /// LD B, A
77    pub fn ld_b_a(&mut self) {
78        self.emit(&[0x47]);
79    }
80
81    /// LD C, A
82    pub fn ld_c_a(&mut self) {
83        self.emit(&[0x4F]);
84    }
85
86    /// LD D, A
87    pub fn ld_d_a(&mut self) {
88        self.emit(&[0x57]);
89    }
90
91    /// LD E, A
92    pub fn ld_e_a(&mut self) {
93        self.emit(&[0x5F]);
94    }
95
96    /// LD A, (nn)
97    pub fn ld_a_addr(&mut self, addr: u16) {
98        self.emit(&[0x3A]);
99        self.emit_word(addr);
100    }
101
102    /// LD (nn), A
103    pub fn ld_addr_a(&mut self, addr: u16) {
104        self.emit(&[0x32]);
105        self.emit_word(addr);
106    }
107
108    // ========== 16-bit Load Instructions ==========
109
110    /// LD BC, nn
111    pub fn ld_bc(&mut self, nn: u16) {
112        self.emit(&[0x01]);
113        self.emit_word(nn);
114    }
115
116    /// LD DE, nn
117    pub fn ld_de(&mut self, nn: u16) {
118        self.emit(&[0x11]);
119        self.emit_word(nn);
120    }
121
122    /// LD HL, nn
123    pub fn ld_hl(&mut self, nn: u16) {
124        self.emit(&[0x21]);
125        self.emit_word(nn);
126    }
127
128    /// LD SP, nn
129    pub fn ld_sp(&mut self, nn: u16) {
130        self.emit(&[0x31]);
131        self.emit_word(nn);
132    }
133
134    /// LD HL, (nn)
135    pub fn ld_hl_addr(&mut self, addr: u16) {
136        self.emit(&[0x2A]);
137        self.emit_word(addr);
138    }
139
140    /// LD (nn), HL
141    pub fn ld_addr_hl(&mut self, addr: u16) {
142        self.emit(&[0x22]);
143        self.emit_word(addr);
144    }
145
146    /// LD DE, (nn) - ED instruction
147    pub fn ld_de_addr(&mut self, addr: u16) {
148        self.emit(&[0xED, 0x5B]);
149        self.emit_word(addr);
150    }
151
152    /// LD (nn), DE - ED instruction
153    pub fn ld_addr_de(&mut self, addr: u16) {
154        self.emit(&[0xED, 0x53]);
155        self.emit_word(addr);
156    }
157
158    /// LD SP, HL
159    pub fn ld_sp_hl(&mut self) {
160        self.emit(&[0xF9]);
161    }
162
163    // ========== Stack Operations ==========
164
165    /// PUSH AF
166    pub fn push_af(&mut self) {
167        self.emit(&[0xF5]);
168    }
169
170    /// PUSH BC
171    pub fn push_bc(&mut self) {
172        self.emit(&[0xC5]);
173    }
174
175    /// PUSH DE
176    pub fn push_de(&mut self) {
177        self.emit(&[0xD5]);
178    }
179
180    /// PUSH HL
181    pub fn push_hl(&mut self) {
182        self.emit(&[0xE5]);
183    }
184
185    /// POP AF
186    pub fn pop_af(&mut self) {
187        self.emit(&[0xF1]);
188    }
189
190    /// POP BC
191    pub fn pop_bc(&mut self) {
192        self.emit(&[0xC1]);
193    }
194
195    /// POP DE
196    pub fn pop_de(&mut self) {
197        self.emit(&[0xD1]);
198    }
199
200    /// POP HL
201    pub fn pop_hl(&mut self) {
202        self.emit(&[0xE1]);
203    }
204
205    // ========== Exchange Instructions ==========
206
207    /// EX DE, HL
208    pub fn ex_de_hl(&mut self) {
209        self.emit(&[0xEB]);
210    }
211
212    /// EX AF, AF'
213    pub fn ex_af(&mut self) {
214        self.emit(&[0x08]);
215    }
216
217    /// EXX
218    pub fn exx(&mut self) {
219        self.emit(&[0xD9]);
220    }
221
222    // ========== Arithmetic - 8 bit ==========
223
224    /// ADD A, n
225    pub fn add_a(&mut self, n: u8) {
226        self.emit(&[0xC6, n]);
227    }
228
229    /// ADD A, B
230    pub fn add_a_b(&mut self) {
231        self.emit(&[0x80]);
232    }
233
234    /// ADD A, (HL)
235    pub fn add_a_hl_ind(&mut self) {
236        self.emit(&[0x86]);
237    }
238
239    /// SUB n
240    pub fn sub_a(&mut self, n: u8) {
241        self.emit(&[0xD6, n]);
242    }
243
244    /// SUB B
245    pub fn sub_b(&mut self) {
246        self.emit(&[0x90]);
247    }
248
249    /// INC A
250    pub fn inc_a(&mut self) {
251        self.emit(&[0x3C]);
252    }
253
254    /// INC B
255    pub fn inc_b(&mut self) {
256        self.emit(&[0x04]);
257    }
258
259    /// INC C
260    pub fn inc_c(&mut self) {
261        self.emit(&[0x0C]);
262    }
263
264    /// DEC A
265    pub fn dec_a(&mut self) {
266        self.emit(&[0x3D]);
267    }
268
269    /// DEC B
270    pub fn dec_b(&mut self) {
271        self.emit(&[0x05]);
272    }
273
274    /// DEC C
275    pub fn dec_c(&mut self) {
276        self.emit(&[0x0D]);
277    }
278
279    // ========== Arithmetic - 16 bit ==========
280
281    /// INC HL
282    pub fn inc_hl(&mut self) {
283        self.emit(&[0x23]);
284    }
285
286    /// INC DE
287    pub fn inc_de(&mut self) {
288        self.emit(&[0x13]);
289    }
290
291    /// INC BC
292    pub fn inc_bc(&mut self) {
293        self.emit(&[0x03]);
294    }
295
296    /// DEC HL
297    pub fn dec_hl(&mut self) {
298        self.emit(&[0x2B]);
299    }
300
301    /// DEC DE
302    pub fn dec_de(&mut self) {
303        self.emit(&[0x1B]);
304    }
305
306    /// DEC BC
307    pub fn dec_bc(&mut self) {
308        self.emit(&[0x0B]);
309    }
310
311    /// ADD HL, BC
312    pub fn add_hl_bc(&mut self) {
313        self.emit(&[0x09]);
314    }
315
316    /// ADD HL, DE
317    pub fn add_hl_de(&mut self) {
318        self.emit(&[0x19]);
319    }
320
321    /// ADD HL, HL
322    pub fn add_hl_hl(&mut self) {
323        self.emit(&[0x29]);
324    }
325
326    /// SBC HL, DE
327    pub fn sbc_hl_de(&mut self) {
328        self.emit(&[0xED, 0x52]);
329    }
330
331    /// SBC HL, BC
332    pub fn sbc_hl_bc(&mut self) {
333        self.emit(&[0xED, 0x42]);
334    }
335
336    // ========== Logic ==========
337
338    /// AND n
339    pub fn and_a(&mut self, n: u8) {
340        self.emit(&[0xE6, n]);
341    }
342
343    /// OR n
344    pub fn or_a(&mut self, n: u8) {
345        self.emit(&[0xF6, n]);
346    }
347
348    /// OR A (common for flag check)
349    pub fn or_a_a(&mut self) {
350        self.emit(&[0xB7]);
351    }
352
353    /// OR B
354    pub fn or_b(&mut self) {
355        self.emit(&[0xB0]);
356    }
357
358    /// OR L
359    pub fn or_l(&mut self) {
360        self.emit(&[0xB5]);
361    }
362
363    /// XOR A
364    pub fn xor_a(&mut self) {
365        self.emit(&[0xAF]);
366    }
367
368    /// XOR n
369    pub fn xor_n(&mut self, n: u8) {
370        self.emit(&[0xEE, n]);
371    }
372
373    /// CP n
374    pub fn cp(&mut self, n: u8) {
375        self.emit(&[0xFE, n]);
376    }
377
378    /// CP B
379    pub fn cp_b(&mut self) {
380        self.emit(&[0xB8]);
381    }
382
383    /// CP (HL)
384    pub fn cp_hl_ind(&mut self) {
385        self.emit(&[0xBE]);
386    }
387
388    /// CPL (complement A)
389    pub fn cpl(&mut self) {
390        self.emit(&[0x2F]);
391    }
392
393    // ========== Jumps ==========
394
395    /// JP nn (with fixup)
396    pub fn jp(&mut self, label: &str) {
397        self.emit(&[0xC3]);
398        self.fixup(label);
399    }
400
401    /// JP nn (absolute address)
402    pub fn jp_addr(&mut self, addr: u16) {
403        self.emit(&[0xC3]);
404        self.emit_word(addr);
405    }
406
407    /// JP Z, nn
408    pub fn jp_z(&mut self, label: &str) {
409        self.emit(&[0xCA]);
410        self.fixup(label);
411    }
412
413    /// JP NZ, nn
414    pub fn jp_nz(&mut self, label: &str) {
415        self.emit(&[0xC2]);
416        self.fixup(label);
417    }
418
419    /// JP C, nn
420    pub fn jp_c(&mut self, label: &str) {
421        self.emit(&[0xDA]);
422        self.fixup(label);
423    }
424
425    /// JP NC, nn
426    pub fn jp_nc(&mut self, label: &str) {
427        self.emit(&[0xD2]);
428        self.fixup(label);
429    }
430
431    /// JP P, nn (positive/sign flag clear)
432    pub fn jp_p(&mut self, label: &str) {
433        self.emit(&[0xF2]);
434        self.fixup(label);
435    }
436
437    /// JP M, nn (minus/sign flag set)
438    pub fn jp_m(&mut self, label: &str) {
439        self.emit(&[0xFA]);
440        self.fixup(label);
441    }
442
443    /// JP (HL)
444    pub fn jp_hl(&mut self) {
445        self.emit(&[0xE9]);
446    }
447
448    /// JR e (relative jump, label must be defined)
449    pub fn jr(&mut self, label: &str) {
450        self.emit(&[0x18]);
451        self.emit_relative(label);
452    }
453
454    /// JR Z, e
455    pub fn jr_z(&mut self, label: &str) {
456        self.emit(&[0x28]);
457        self.emit_relative(label);
458    }
459
460    /// JR NZ, e
461    pub fn jr_nz(&mut self, label: &str) {
462        self.emit(&[0x20]);
463        self.emit_relative(label);
464    }
465
466    /// JR C, e
467    pub fn jr_c(&mut self, label: &str) {
468        self.emit(&[0x38]);
469        self.emit_relative(label);
470    }
471
472    /// JR NC, e
473    pub fn jr_nc(&mut self, label: &str) {
474        self.emit(&[0x30]);
475        self.emit_relative(label);
476    }
477
478    /// DJNZ e (decrement B, jump if not zero)
479    pub fn djnz(&mut self, label: &str) {
480        self.emit(&[0x10]);
481        self.emit_relative(label);
482    }
483
484    // ========== Calls and Returns ==========
485
486    /// CALL nn (with fixup)
487    pub fn call(&mut self, label: &str) {
488        self.emit(&[0xCD]);
489        self.fixup(label);
490    }
491
492    /// CALL nn (absolute address)
493    pub fn call_addr(&mut self, addr: u16) {
494        self.emit(&[0xCD]);
495        self.emit_word(addr);
496    }
497
498    /// CALL Z, nn
499    pub fn call_z(&mut self, label: &str) {
500        self.emit(&[0xCC]);
501        self.fixup(label);
502    }
503
504    /// CALL NZ, nn
505    pub fn call_nz(&mut self, label: &str) {
506        self.emit(&[0xC4]);
507        self.fixup(label);
508    }
509
510    /// RET
511    pub fn ret(&mut self) {
512        self.emit(&[0xC9]);
513    }
514
515    /// RET Z
516    pub fn ret_z(&mut self) {
517        self.emit(&[0xC8]);
518    }
519
520    /// RET NZ
521    pub fn ret_nz(&mut self) {
522        self.emit(&[0xC0]);
523    }
524
525    /// RET C
526    pub fn ret_c(&mut self) {
527        self.emit(&[0xD8]);
528    }
529
530    /// RET NC
531    pub fn ret_nc(&mut self) {
532        self.emit(&[0xD0]);
533    }
534
535    // ========== I/O ==========
536
537    /// IN A, (n)
538    pub fn in_a(&mut self, port: u8) {
539        self.emit(&[0xDB, port]);
540    }
541
542    /// OUT (n), A
543    pub fn out_a(&mut self, port: u8) {
544        self.emit(&[0xD3, port]);
545    }
546
547    // ========== Misc ==========
548
549    /// NOP
550    pub fn nop(&mut self) {
551        self.emit(&[0x00]);
552    }
553
554    /// HALT
555    pub fn halt(&mut self) {
556        self.emit(&[0x76]);
557    }
558
559    /// DI (disable interrupts)
560    pub fn di(&mut self) {
561        self.emit(&[0xF3]);
562    }
563
564    /// EI (enable interrupts)
565    pub fn ei(&mut self) {
566        self.emit(&[0xFB]);
567    }
568
569    /// SCF (set carry flag)
570    pub fn scf(&mut self) {
571        self.emit(&[0x37]);
572    }
573
574    /// CCF (complement carry flag)
575    pub fn ccf(&mut self) {
576        self.emit(&[0x3F]);
577    }
578
579    // ========== Bit Operations ==========
580
581    /// BIT b, A
582    pub fn bit_a(&mut self, bit: u8) {
583        self.emit(&[0xCB, 0x47 | (bit << 3)]);
584    }
585
586    /// SET b, A
587    pub fn set_a(&mut self, bit: u8) {
588        self.emit(&[0xCB, 0xC7 | (bit << 3)]);
589    }
590
591    /// RES b, A
592    pub fn res_a(&mut self, bit: u8) {
593        self.emit(&[0xCB, 0x87 | (bit << 3)]);
594    }
595
596    /// RLA (rotate left through carry)
597    pub fn rla(&mut self) {
598        self.emit(&[0x17]);
599    }
600
601    /// RRA (rotate right through carry)
602    pub fn rra(&mut self) {
603        self.emit(&[0x1F]);
604    }
605
606    /// RLCA (rotate left circular)
607    pub fn rlca(&mut self) {
608        self.emit(&[0x07]);
609    }
610
611    /// RRCA (rotate right circular)
612    pub fn rrca(&mut self) {
613        self.emit(&[0x0F]);
614    }
615
616    /// SLA A (shift left arithmetic)
617    pub fn sla_a(&mut self) {
618        self.emit(&[0xCB, 0x27]);
619    }
620
621    /// SRA A (shift right arithmetic)
622    pub fn sra_a(&mut self) {
623        self.emit(&[0xCB, 0x2F]);
624    }
625
626    /// SRL A (shift right logical)
627    pub fn srl_a(&mut self) {
628        self.emit(&[0xCB, 0x3F]);
629    }
630}
631
632#[cfg(test)]
633mod tests {
634    use super::*;
635
636    #[test]
637    fn test_ld_a() {
638        let mut cg = CodeGen::new();
639        cg.ld_a(0x42);
640        assert_eq!(cg.rom(), &[0x3E, 0x42]);
641    }
642
643    #[test]
644    fn test_ld_hl() {
645        let mut cg = CodeGen::new();
646        cg.ld_hl(0x1234);
647        assert_eq!(cg.rom(), &[0x21, 0x34, 0x12]);
648    }
649
650    #[test]
651    fn test_call_and_ret() {
652        let mut cg = CodeGen::new();
653        cg.label("start");
654        cg.call("func");
655        cg.halt();
656        cg.label("func");
657        cg.ret();
658        cg.resolve_fixups();
659
660        // CALL should point to func at offset 4
661        assert_eq!(cg.rom()[0], 0xCD);
662        assert_eq!(cg.rom()[1], 0x04);
663        assert_eq!(cg.rom()[2], 0x00);
664    }
665
666    #[test]
667    fn test_8bit_loads() {
668        let mut cg = CodeGen::new();
669        cg.ld_b(0x10);
670        cg.ld_c(0x20);
671        cg.ld_d(0x30);
672        cg.ld_e(0x40);
673        assert_eq!(cg.rom(), &[0x06, 0x10, 0x0E, 0x20, 0x16, 0x30, 0x1E, 0x40]);
674    }
675
676    #[test]
677    fn test_16bit_loads() {
678        let mut cg = CodeGen::new();
679        cg.ld_bc(0x1234);
680        cg.ld_de(0x5678);
681        cg.ld_sp(0x3FFF);
682        assert_eq!(cg.rom(), &[
683            0x01, 0x34, 0x12,  // LD BC, 0x1234
684            0x11, 0x78, 0x56,  // LD DE, 0x5678
685            0x31, 0xFF, 0x3F,  // LD SP, 0x3FFF
686        ]);
687    }
688
689    #[test]
690    fn test_register_transfers() {
691        let mut cg = CodeGen::new();
692        cg.ld_a_b();
693        cg.ld_a_c();
694        cg.ld_b_a();
695        cg.ld_c_a();
696        assert_eq!(cg.rom(), &[0x78, 0x79, 0x47, 0x4F]);
697    }
698
699    #[test]
700    fn test_memory_access() {
701        let mut cg = CodeGen::new();
702        cg.ld_a_hl_ind();
703        cg.ld_hl_ind_a();
704        cg.ld_a_addr(0x3000);
705        cg.ld_addr_a(0x3000);
706        assert_eq!(cg.rom(), &[
707            0x7E,              // LD A, (HL)
708            0x77,              // LD (HL), A
709            0x3A, 0x00, 0x30,  // LD A, (0x3000)
710            0x32, 0x00, 0x30,  // LD (0x3000), A
711        ]);
712    }
713
714    #[test]
715    fn test_stack_operations() {
716        let mut cg = CodeGen::new();
717        cg.push_af();
718        cg.push_bc();
719        cg.push_de();
720        cg.push_hl();
721        cg.pop_hl();
722        cg.pop_de();
723        cg.pop_bc();
724        cg.pop_af();
725        assert_eq!(cg.rom(), &[0xF5, 0xC5, 0xD5, 0xE5, 0xE1, 0xD1, 0xC1, 0xF1]);
726    }
727
728    #[test]
729    fn test_arithmetic() {
730        let mut cg = CodeGen::new();
731        cg.add_a(5);
732        cg.sub_a(3);
733        cg.inc_a();
734        cg.dec_a();
735        cg.inc_hl();
736        cg.dec_de();
737        assert_eq!(cg.rom(), &[
738            0xC6, 0x05,  // ADD A, 5
739            0xD6, 0x03,  // SUB 3
740            0x3C,        // INC A
741            0x3D,        // DEC A
742            0x23,        // INC HL
743            0x1B,        // DEC DE
744        ]);
745    }
746
747    #[test]
748    fn test_16bit_arithmetic() {
749        let mut cg = CodeGen::new();
750        cg.add_hl_bc();
751        cg.add_hl_de();
752        cg.add_hl_hl();
753        cg.sbc_hl_de();
754        assert_eq!(cg.rom(), &[
755            0x09,        // ADD HL, BC
756            0x19,        // ADD HL, DE
757            0x29,        // ADD HL, HL
758            0xED, 0x52,  // SBC HL, DE
759        ]);
760    }
761
762    #[test]
763    fn test_logic() {
764        let mut cg = CodeGen::new();
765        cg.and_a(0x0F);
766        cg.or_a(0xF0);
767        cg.xor_a();
768        cg.cp(0x0D);
769        cg.cpl();
770        assert_eq!(cg.rom(), &[
771            0xE6, 0x0F,  // AND 0x0F
772            0xF6, 0xF0,  // OR 0xF0
773            0xAF,        // XOR A
774            0xFE, 0x0D,  // CP 0x0D
775            0x2F,        // CPL
776        ]);
777    }
778
779    #[test]
780    fn test_jumps() {
781        let mut cg = CodeGen::new();
782        cg.label("target");
783        cg.nop();
784        cg.jp("target");
785        cg.jp_z("target");
786        cg.jp_nz("target");
787        cg.jp_c("target");
788        cg.jp_nc("target");
789        cg.resolve_fixups();
790
791        assert_eq!(cg.rom()[0], 0x00);  // NOP
792        assert_eq!(cg.rom()[1], 0xC3);  // JP
793        assert_eq!(cg.rom()[4], 0xCA);  // JP Z
794        assert_eq!(cg.rom()[7], 0xC2);  // JP NZ
795        assert_eq!(cg.rom()[10], 0xDA); // JP C
796        assert_eq!(cg.rom()[13], 0xD2); // JP NC
797    }
798
799    #[test]
800    fn test_relative_jumps() {
801        let mut cg = CodeGen::new();
802        cg.label("loop");
803        cg.nop();
804        cg.nop();
805        cg.jr("loop");
806
807        // JR offset should be -4 (back 4 bytes from after the JR instruction)
808        assert_eq!(cg.rom(), &[0x00, 0x00, 0x18, 0xFC]); // 0xFC = -4 signed
809    }
810
811    #[test]
812    fn test_djnz() {
813        let mut cg = CodeGen::new();
814        cg.ld_b(10);
815        cg.label("loop");
816        cg.dec_a();
817        cg.djnz("loop");
818
819        assert_eq!(cg.rom(), &[
820            0x06, 0x0A,  // LD B, 10
821            0x3D,        // DEC A
822            0x10, 0xFD,  // DJNZ loop (-3)
823        ]);
824    }
825
826    #[test]
827    fn test_io() {
828        let mut cg = CodeGen::new();
829        cg.in_a(0x80);
830        cg.out_a(0x81);
831        assert_eq!(cg.rom(), &[0xDB, 0x80, 0xD3, 0x81]);
832    }
833
834    #[test]
835    fn test_misc() {
836        let mut cg = CodeGen::new();
837        cg.nop();
838        cg.halt();
839        cg.di();
840        cg.ei();
841        cg.ex_de_hl();
842        assert_eq!(cg.rom(), &[0x00, 0x76, 0xF3, 0xFB, 0xEB]);
843    }
844
845    #[test]
846    fn test_conditional_returns() {
847        let mut cg = CodeGen::new();
848        cg.ret();
849        cg.ret_z();
850        cg.ret_nz();
851        cg.ret_c();
852        cg.ret_nc();
853        assert_eq!(cg.rom(), &[0xC9, 0xC8, 0xC0, 0xD8, 0xD0]);
854    }
855
856    #[test]
857    fn test_bit_operations() {
858        let mut cg = CodeGen::new();
859        cg.bit_a(0);
860        cg.bit_a(7);
861        cg.set_a(3);
862        cg.res_a(5);
863        assert_eq!(cg.rom(), &[
864            0xCB, 0x47,  // BIT 0, A
865            0xCB, 0x7F,  // BIT 7, A
866            0xCB, 0xDF,  // SET 3, A
867            0xCB, 0xAF,  // RES 5, A
868        ]);
869    }
870
871    #[test]
872    fn test_rotates() {
873        let mut cg = CodeGen::new();
874        cg.rla();
875        cg.rra();
876        cg.rlca();
877        cg.rrca();
878        assert_eq!(cg.rom(), &[0x17, 0x1F, 0x07, 0x0F]);
879    }
880}