cpclib_tokens/
builder.rs

1#![allow(missing_docs)]
2
3use cpclib_common::smol_str::SmolStr;
4use paste;
5
6/// ! Utility code to build more easily tokens to manipulate in code generators
7use crate::tokens::*;
8
9/// NOP instruction
10pub fn nop() -> Token {
11    token_for_opcode_no_arg(Mnemonic::Nop)
12}
13
14pub fn halt() -> Token {
15    token_for_opcode_no_arg(Mnemonic::Halt)
16}
17
18pub fn di() -> Token {
19    token_for_opcode_no_arg(Mnemonic::Di)
20}
21
22pub fn ei() -> Token {
23    token_for_opcode_no_arg(Mnemonic::Ei)
24}
25
26pub fn ind() -> Token {
27    token_for_opcode_no_arg(Mnemonic::Ind)
28}
29
30pub fn indr() -> Token {
31    token_for_opcode_no_arg(Mnemonic::Indr)
32}
33
34pub fn ini() -> Token {
35    token_for_opcode_no_arg(Mnemonic::Ini)
36}
37
38pub fn inir() -> Token {
39    token_for_opcode_no_arg(Mnemonic::Inir)
40}
41
42pub fn outd() -> Token {
43    token_for_opcode_no_arg(Mnemonic::Outd)
44}
45
46pub fn outdr() -> Token {
47    token_for_opcode_no_arg(Mnemonic::Otdr)
48}
49
50pub fn outi() -> Token {
51    token_for_opcode_no_arg(Mnemonic::Outi)
52}
53
54pub fn outir() -> Token {
55    token_for_opcode_no_arg(Mnemonic::Otir)
56}
57
58pub fn neg() -> Token {
59    token_for_opcode_no_arg(Mnemonic::Neg)
60}
61
62pub fn exa() -> Token {
63    token_for_opcode_no_arg(Mnemonic::ExAf)
64}
65
66pub fn ex_hl_de() -> Token {
67    token_for_opcode_no_arg(Mnemonic::ExHlDe)
68}
69
70/// Generate org directive
71pub fn org<E: Into<Expr>>(val: E) -> Token {
72    Token::Org {
73        val1: val.into(),
74        val2: None
75    }
76}
77
78pub fn equ<S: AsRef<str>, E: Into<Expr>>(label: S, expr: E) -> Token {
79    Token::Equ {
80        label: label.as_ref().into(),
81        expr: expr.into()
82    }
83}
84
85#[allow(missing_docs)]
86pub fn label<S: AsRef<str>>(label: S) -> Token {
87    Token::Label(label.as_ref().into())
88}
89
90/// Generate an ASSERT token from the string description of the expression
91pub fn assert_str<S: AsRef<str>>(expr: S) -> Token {
92    Token::Assert(expr.as_ref().into(), None)
93}
94
95/// Generate a call
96
97#[allow(missing_docs)]
98pub fn comment<S: AsRef<str>>(label: S) -> Token {
99    Token::Comment(label.as_ref().to_owned())
100}
101
102pub fn r#if(cond: TestKind, lst: Listing) -> Token {
103    IfBuilder::default().condition(cond, lst).build()
104}
105
106/// Generate defs directive
107pub fn defs_expr<E: Into<Expr>>(expr: E) -> Token {
108    Token::Defs(vec![(expr.into(), None)])
109}
110
111/// Generate defs directive
112pub fn defs_expr_expr<E1: Into<Expr>, E2: Into<Expr>>(count: E1, value: E2) -> Token {
113    Token::Defs(vec![(count.into(), value.into().into())])
114}
115
116/// Generate defw directive with one argument
117pub fn defb<E: Into<Expr>>(val: E) -> Token {
118    Token::Defb(vec![val.into()])
119}
120
121/// Generate defb directive from a slice of expression
122pub fn defb_elements<E: Into<Expr>>(elements: &[E]) -> Token
123where E: Clone {
124    let mut data = Vec::new();
125    for val in elements {
126        let val = val.clone();
127        let expr = val.into();
128        data.push(expr);
129    }
130    Token::Defb(data)
131}
132
133/// Generate defw directive with one argument
134pub fn defw<E: Into<Expr>>(val: E) -> Token {
135    Token::Defw(vec![val.into()])
136}
137
138/// DJNZ opcode
139pub fn djnz_expr<E: Into<Expr>>(expr: E) -> Token {
140    mnemonic_with_single_expr(Mnemonic::Djnz, expr)
141}
142
143/// Call opcode
144pub fn call_expr<E: Into<Expr>>(expr: E) -> Token {
145    mnemonic_with_single_expr(Mnemonic::Call, expr)
146}
147
148/// Use this function to generate tokens having a mnemonic with a single expression argument
149/// TODO write a macro instead and automatically generate all the cases
150fn mnemonic_with_single_expr<E: Into<Expr>>(mne: Mnemonic, expr: E) -> Token {
151    Token::OpCode(mne, Some(expr.into().into()), None, None)
152}
153
154#[allow(missing_docs)]
155pub fn out_c_b() -> Token {
156    out_c_register8(Register8::B)
157}
158#[allow(missing_docs)]
159pub fn out_c_c() -> Token {
160    out_c_register8(Register8::C)
161}
162#[allow(missing_docs)]
163pub fn out_c_d() -> Token {
164    out_c_register8(Register8::D)
165}
166#[allow(missing_docs)]
167pub fn out_c_e() -> Token {
168    out_c_register8(Register8::E)
169}
170#[allow(missing_docs)]
171pub fn out_c_h() -> Token {
172    out_c_register8(Register8::H)
173}
174#[allow(missing_docs)]
175pub fn out_c_l() -> Token {
176    out_c_register8(Register8::L)
177}
178#[allow(missing_docs)]
179pub fn out_c_a() -> Token {
180    out_c_register8(Register8::A)
181}
182
183#[allow(missing_docs)]
184pub fn out_c_register8(reg: Register8) -> Token {
185    token_for_opcode_two_args(Mnemonic::Out, DataAccess::PortC, reg.into())
186}
187
188#[allow(missing_docs)]
189pub fn push_af() -> Token {
190    push_or_pop(Mnemonic::Push, Register16::Af)
191}
192
193#[allow(missing_docs)]
194pub fn push_bc() -> Token {
195    push_or_pop(Mnemonic::Push, Register16::Bc)
196}
197
198#[allow(missing_docs)]
199pub fn push_de() -> Token {
200    push_or_pop(Mnemonic::Push, Register16::De)
201}
202
203#[allow(missing_docs)]
204pub fn push_hl() -> Token {
205    push_or_pop(Mnemonic::Push, Register16::Hl)
206}
207
208#[allow(missing_docs)]
209pub fn pop_af() -> Token {
210    push_or_pop(Mnemonic::Pop, Register16::Af)
211}
212
213#[allow(missing_docs)]
214pub fn pop_bc() -> Token {
215    push_or_pop(Mnemonic::Pop, Register16::Bc)
216}
217
218#[allow(missing_docs)]
219pub fn pop_de() -> Token {
220    push_or_pop(Mnemonic::Pop, Register16::De)
221}
222
223#[allow(missing_docs)]
224pub fn pop_hl() -> Token {
225    push_or_pop(Mnemonic::Pop, Register16::Hl)
226}
227
228#[inline]
229fn push_or_pop(op: Mnemonic, reg: Register16) -> Token {
230    token_for_opcode_one_arg(op, reg.into())
231}
232
233#[allow(missing_docs)]
234pub fn push_ix() -> Token {
235    Token::OpCode(
236        Mnemonic::Push,
237        Some(DataAccess::IndexRegister16(IndexRegister16::Ix)),
238        None,
239        None
240    )
241}
242
243#[allow(missing_docs)]
244pub fn push_iy() -> Token {
245    Token::OpCode(
246        Mnemonic::Push,
247        Some(DataAccess::IndexRegister16(IndexRegister16::Iy)),
248        None,
249        None
250    )
251}
252
253#[allow(missing_docs)]
254pub fn pop_ix() -> Token {
255    Token::OpCode(
256        Mnemonic::Pop,
257        Some(DataAccess::IndexRegister16(IndexRegister16::Ix)),
258        None,
259        None
260    )
261}
262
263#[allow(missing_docs)]
264pub fn pop_iy() -> Token {
265    Token::OpCode(
266        Mnemonic::Pop,
267        Some(DataAccess::IndexRegister16(IndexRegister16::Iy)),
268        None,
269        None
270    )
271}
272
273/// Ret token
274pub fn ret() -> Token {
275    Token::OpCode(Mnemonic::Ret, None, None, None)
276}
277
278#[allow(missing_docs)]
279pub fn breakpoint_winape() -> Token {
280    Token::Defb(vec![Expr::Value(0xED), Expr::Value(0xFF)])
281}
282
283#[allow(missing_docs)]
284pub fn breakpoint_snapshot() -> Token {
285    todo!()
286}
287
288#[allow(missing_docs)]
289pub fn jp_label(label: &str) -> Token {
290    token_for_opcode_latest_arg(Mnemonic::Jp, label.into())
291}
292
293#[allow(missing_docs)]
294pub fn jp_ix() -> Token {
295    token_for_opcode_latest_arg(
296        Mnemonic::Jp,
297        DataAccess::MemoryIndexRegister16(IndexRegister16::Ix)
298    )
299}
300
301#[allow(missing_docs)]
302pub fn jp_iy() -> Token {
303    token_for_opcode_latest_arg(
304        Mnemonic::Jp,
305        DataAccess::MemoryIndexRegister16(IndexRegister16::Iy)
306    )
307}
308
309#[allow(missing_docs)]
310pub fn jp_hl() -> Token {
311    token_for_opcode_latest_arg(Mnemonic::Jp, DataAccess::MemoryRegister16(Register16::Hl))
312}
313
314#[allow(missing_docs)]
315pub fn exx() -> Token {
316    token_for_opcode_no_arg(Mnemonic::Exx)
317}
318
319#[allow(missing_docs)]
320pub fn incbin<S: Into<SmolStr>>(fname: S) -> Token {
321    Token::Incbin {
322        fname: Expr::String(fname.into()),
323        transformation: BinaryTransformation::None,
324        offset: None,
325        length: None,
326        extended_offset: None,
327        off: false
328    }
329}
330
331macro_rules! math_op_r8 {
332    ($($reg:ident)*) => {$(
333        paste::paste! {
334            pub fn [<add_ $reg:lower>] () -> Token {
335                token_for_opcode_two_args(
336                    Mnemonic::Add,
337                    Register8::A.into(),
338                    Register8::$reg.into()
339                )
340            }
341
342            pub fn [<sub_ $reg:lower>] () -> Token {
343                token_for_opcode_two_args(
344                    Mnemonic::Sub,
345                    Register8::A.into(),
346                    Register8::$reg.into()
347                )
348            }
349
350        }
351    )*}
352}
353math_op_r8! { A B C D E H L}
354
355macro_rules! inc_r8 {
356    ($($reg:ident)*) => {$(
357        paste::paste! {
358            /// Generate the opcode inc $reg
359            #[allow(missing_docs)] pub fn [<inc_ $reg:lower>] () -> Token {
360                token_for_opcode_one_arg(
361                    Mnemonic::Inc,
362                    Register8::$reg.into()
363                )
364            }
365
366            /// Generate the opcode dec $reg
367            #[allow(missing_docs)] pub fn [<dec_ $reg:lower>] () -> Token {
368                token_for_opcode_one_arg(
369                    Mnemonic::Dec,
370                    Register8::$reg.into()
371                )
372            }
373        }
374    )*}
375}
376inc_r8! { A B C D E H L}
377
378macro_rules! inc_r16 {
379    ($($reg:ident)*) => {$(
380        paste::paste! {
381            /// Generate the opcode inc $reg
382            #[allow(missing_docs)] pub fn [<inc_ $reg:lower>] () -> Token {
383                token_for_opcode_one_arg(
384                    Mnemonic::Inc,
385                    Register16::$reg.into()
386                )
387            }
388
389            /// Generate the opcode dec $reg
390            #[allow(missing_docs)] pub fn [<dec_ $reg:lower>] () -> Token {
391                token_for_opcode_one_arg(
392                    Mnemonic::Dec,
393                    Register16::$reg.into()
394                )
395            }
396        }
397    )*}
398}
399inc_r16! {Af Bc De Hl}
400
401pub fn ld_r8_expr<R: Into<Register8>, E: Into<Expr>>(r: R, e: E) -> Token {
402    token_for_opcode_two_args(Mnemonic::Ld, r.into().into(), e.into().into())
403}
404
405pub fn ld_r16_expr<R: Into<Register16>, E: Into<Expr>>(r: R, e: E) -> Token {
406    token_for_opcode_two_args(Mnemonic::Ld, r.into().into(), e.into().into())
407}
408
409/// I have clear doubt that  this exists really
410#[allow(missing_docs)]
411pub fn ld_l_mem_ix(expr: Expr) -> Token {
412    token_for_opcode_two_args(
413        Mnemonic::Ld,
414        Register8::L.into(),
415        DataAccess::IndexRegister16WithIndex(
416            IndexRegister16::Ix,
417            if expr.is_negated() {
418                BinaryOperation::Sub
419            }
420            else {
421                BinaryOperation::Add
422            },
423            if expr.is_negated() { expr.neg() } else { expr }
424        )
425    )
426}
427
428pub fn ld_mem_bc_a() -> Token {
429    token_for_opcode_two_args(
430        Mnemonic::Ld,
431        DataAccess::MemoryRegister16(Register16::Bc),
432        DataAccess::Register8(Register8::A)
433    )
434}
435
436pub fn ld_mem_de_a() -> Token {
437    token_for_opcode_two_args(
438        Mnemonic::Ld,
439        DataAccess::MemoryRegister16(Register16::Bc),
440        DataAccess::Register8(Register8::A)
441    )
442}
443
444pub fn ld_a_mem_bc() -> Token {
445    token_for_opcode_two_args(
446        Mnemonic::Ld,
447        DataAccess::Register8(Register8::A),
448        DataAccess::MemoryRegister16(Register16::Bc)
449    )
450}
451
452pub fn ld_a_mem_de() -> Token {
453    token_for_opcode_two_args(
454        Mnemonic::Ld,
455        DataAccess::Register8(Register8::A),
456        DataAccess::MemoryRegister16(Register16::De)
457    )
458}
459
460macro_rules! ld_r16_expr {
461    ($($reg:ident)*) => {$(
462        paste::paste! {
463            /// Generate the opcode LD $reg, expr
464            #[allow(missing_docs)] pub fn [<ld_ $reg:lower _expr>]<E:Into<Expr>> (val: E) -> Token {
465                token_for_opcode_two_args(
466                    Mnemonic::Ld,
467                    Register16::$reg.into(),
468                    val.into().into()
469                )
470            }
471        }
472    )*}
473}
474
475// TODO remove these extra uneeded arguments
476ld_r16_expr! {
477    Af
478    Bc
479    De
480    Hl
481    Sp
482}
483
484macro_rules! ld_r8_expr {
485    ($($reg:ident)*) => {$(
486        paste::paste! {
487            /// Generate the opcode LD $reg, expr
488            #[allow(missing_docs)] pub fn [<ld_ $reg:lower _expr>]<E: Into<Expr>> (val: E) -> Token {
489                token_for_opcode_two_args(
490                    Mnemonic::Ld,
491                    Register8::$reg.into(),
492                    val.into().into()
493                )
494            }
495        }
496    )*}
497}
498
499ld_r8_expr! {
500    A
501    B
502    C
503    D
504    E
505    H
506    L
507}
508
509macro_rules! ld_r8_r8 {
510    ($($reg:ident,$reg2:ident)*) => {$(
511        paste::paste! {
512            /// Generate the opcode LD $reg, reg
513            #[allow(missing_docs)] pub fn [<ld_ $reg:lower _ $reg2:lower>]() -> Token {
514                token_for_opcode_two_args(
515                    Mnemonic::Ld,
516                    Register8::$reg.into(),
517                    Register8::$reg2.into(),
518                )
519            }
520        }
521    )*}
522}
523
524ld_r8_r8! {
525    A,A A,B A,C A,D A,E A,H A,L
526    B,A B,B B,C B,D B,E B,H B,L
527    C,A C,B C,C C,D C,E C,H C,L
528    D,A D,B D,C D,D D,E D,H D,L
529    E,A E,B E,C E,D E,E E,H E,L
530    H,A H,B H,C H,D H,E H,H H,L
531    L,A L,B L,C L,D L,E L,H L,L
532}
533
534#[allow(missing_docs)]
535pub fn ld_mem_expr_a<E: Into<Expr>>(e: E) -> Token {
536    token_for_opcode_two_args(
537        Mnemonic::Ld,
538        DataAccess::Memory(e.into()),
539        Register8::A.into()
540    )
541}
542
543#[allow(missing_docs)]
544pub fn ld_mem_hl_expr<E: Into<Expr>>(e: E) -> Token {
545    let e = e.into();
546    token_for_opcode_two_args(
547        Mnemonic::Ld,
548        DataAccess::MemoryRegister16(Register16::Hl),
549        e.into()
550    )
551}
552
553macro_rules! ld_mem_hl_r8 {
554    ($($reg:ident)*) => {$(
555        paste::paste! {
556            pub fn [<ld_mem_hl_ $reg:lower>]() -> Token {
557                ld_mem_hl_r8(Register8::$reg)
558            }
559
560            pub fn [<ld_ $reg:lower _mem_hl>]() -> Token {
561                ld_register8_mem_hl(Register8::$reg)
562            }
563        }
564    )*}
565}
566
567ld_mem_hl_r8! {
568    A
569    B
570    C
571    D
572    E
573    H
574    L
575}
576
577pub fn ld_mem_hl_r8(reg: Register8) -> Token {
578    token_for_opcode_two_args(
579        Mnemonic::Ld,
580        DataAccess::MemoryRegister16(Register16::Hl),
581        reg.into()
582    )
583}
584
585pub fn ld_register8_mem_hl(reg: Register8) -> Token {
586    token_for_opcode_two_args(
587        Mnemonic::Ld,
588        reg.into(),
589        DataAccess::MemoryRegister16(Register16::Hl)
590    )
591}
592
593#[allow(missing_docs)]
594pub fn ldi() -> Token {
595    token_for_opcode_no_arg(Mnemonic::Ldi)
596}
597
598#[allow(missing_docs)]
599pub fn ldd() -> Token {
600    token_for_opcode_no_arg(Mnemonic::Ldd)
601}
602
603#[allow(missing_docs)]
604pub fn ldir() -> Token {
605    token_for_opcode_no_arg(Mnemonic::Ldir)
606}
607
608#[allow(missing_docs)]
609pub fn lddr() -> Token {
610    token_for_opcode_no_arg(Mnemonic::Lddr)
611}
612
613macro_rules! set_res_reg8 {
614    ($($reg:ident), *) => {$(
615        paste::paste! {
616            #[allow(missing_docs)]
617            #[inline]
618            pub fn [<res_ $reg:lower>](bit: u8) -> Token {
619                res_reg_pos(Register8::$reg, bit)
620            }
621
622            #[allow(missing_docs)]
623            #[inline]
624            pub fn [<set_ $reg:lower>](bit: u8) -> Token {
625                set_reg_pos(Register8::$reg, bit)
626            }
627
628        })*
629    };
630}
631
632set_res_reg8! {A, B, C, D, E, H, L}
633
634#[allow(missing_docs)]
635pub fn set_mem_hl(bit: u8) -> Token {
636    token_for_opcode_two_args(
637        Mnemonic::Set,
638        bit.into(),
639        DataAccess::MemoryRegister16(Register16::Hl)
640    )
641}
642
643#[allow(missing_docs)]
644pub fn res_mem_hl(bit: u8) -> Token {
645    token_for_opcode_two_args(
646        Mnemonic::Res,
647        bit.into(),
648        DataAccess::MemoryRegister16(Register16::Hl)
649    )
650}
651
652#[allow(missing_docs)]
653#[inline]
654pub fn res_reg_pos(reg: Register8, bit: u8) -> Token {
655    token_for_opcode_two_args(Mnemonic::Res, bit.into(), reg.into())
656}
657
658#[allow(missing_docs)]
659#[inline]
660pub fn set_reg_pos(reg: Register8, bit: u8) -> Token {
661    token_for_opcode_two_args(Mnemonic::Set, bit.into(), reg.into())
662}
663
664/// Build a token that represents a mnemonic without any argument
665#[allow(missing_docs)]
666pub fn token_for_opcode_no_arg(mne: Mnemonic) -> Token {
667    Token::OpCode(mne, None, None, None)
668}
669
670/// Build a token that represents a mnemonic with only one argument
671#[allow(missing_docs)]
672pub fn token_for_opcode_one_arg(mne: Mnemonic, data1: DataAccess) -> Token {
673    Token::OpCode(mne, Some(data1), None, None)
674}
675
676/// Build a token that represents a mnemonic with only one argument BUT positioned in the last position (for jp for example)
677#[allow(missing_docs)]
678pub fn token_for_opcode_latest_arg(mne: Mnemonic, data2: DataAccess) -> Token {
679    Token::OpCode(mne, None, Some(data2), None)
680}
681
682/// Build a token that represents a mnemonic with two arguments
683#[allow(missing_docs)]
684pub fn token_for_opcode_two_args(mne: Mnemonic, data1: DataAccess, data2: DataAccess) -> Token {
685    Token::OpCode(mne, Some(data1), Some(data2), None)
686}
687
688#[allow(missing_docs)]
689pub fn section(section: &str) -> Token {
690    Token::Section(section.into())
691}
692
693#[derive(Default)]
694pub struct IfBuilder {
695    conditions: Vec<(TestKind, Listing)>,
696    r#else: Option<Listing>
697}
698
699impl IfBuilder {
700    pub fn build(self) -> Token {
701        assert!(!self.conditions.is_empty());
702        Token::If(self.conditions, self.r#else)
703    }
704
705    pub fn condition(mut self, cond: TestKind, lst: Listing) -> Self {
706        assert!(self.r#else.is_none());
707        self.conditions.push((cond, lst));
708        self
709    }
710
711    pub fn r#else(mut self, lst: Listing) -> Self {
712        self.r#else = Some(lst);
713        self
714    }
715}
716
717#[derive(Default)]
718pub struct ListingBuilder {
719    lst: Listing
720}
721
722macro_rules! ld_r8_expr_builder {
723    ($($reg:ident)*) => {$(
724        paste::paste! {
725            /// Generate the opcode LD $reg, expr
726            pub fn [<ld_ $reg:lower _expr>]<E: Into<Expr>>(mut self, expr: E) -> Self {
727                self.lst.add([<ld_ $reg:lower _expr>](expr));
728                self
729            }
730
731
732            pub fn [<inc_ $reg:lower>](mut self) -> Self {
733                self.lst.add([<inc_ $reg:lower>]());
734                self
735            }
736
737            pub fn [<dec_ $reg:lower>](mut self) -> Self {
738                self.lst.add([<dec_ $reg:lower>]());
739                self
740            }
741        }
742    )*}
743}
744
745macro_rules! ld_r16_expr_builder {
746    ($($reg:ident)*) => {$(
747        paste::paste! {
748            /// Generate the opcode LD $reg, expr
749            pub fn [<ld_ $reg:lower _expr>]<E: Into<Expr>>(mut self, expr: E) -> Self {
750                self.lst.add([<ld_ $reg:lower _expr>](expr));
751                self
752            }
753
754
755            pub fn [<inc_ $reg:lower>](mut self) -> Self {
756                self.lst.add([<inc_ $reg:lower>]());
757                self
758            }
759
760            pub fn [<dec_ $reg:lower>](mut self) -> Self {
761                self.lst.add([<dec_ $reg:lower>]());
762                self
763            }
764
765        }
766    )*}
767}
768
769macro_rules! ld_mem_r16_builder {
770    ($($reg:ident)*) => {$(
771        paste::paste! {
772
773            pub fn [<ld_mem_ $reg:lower _a>](mut self) -> Self {
774                self.lst.add([<ld_mem_ $reg:lower _a>]());
775                self
776            }
777
778            pub fn [<ld_a_ mem_ $reg:lower>](mut self) -> Self {
779                self.lst.add([<ld_a_mem_ $reg:lower>]());
780                self
781            }
782        }
783    )*}
784}
785
786macro_rules! ld_r8_r8_builder {
787    ($($reg1:ident,$reg2:ident)*) => {$(
788        paste::paste! {
789            /// Generate the opcode LD $reg, expr
790            pub fn [<ld_ $reg1:lower _ $reg2:lower>](mut self) -> Self {
791                self.lst.add([<ld_ $reg1:lower _ $reg2:lower>]());
792                self
793            }
794        }
795    )*}
796}
797
798macro_rules! ld_mem_hl_r8_builder {
799    ($($reg:ident)*) => {$(
800        paste::paste! {
801            pub fn [<ld_mem_hl_ $reg:lower>](mut self) -> Self {
802                self.lst.add(ld_mem_hl_r8(Register8::$reg));
803                self
804            }
805
806            pub fn [<ld_ $reg:lower _mem_hl>](mut self) -> Self {
807                self.lst.add(ld_register8_mem_hl(Register8::$reg));
808                self
809            }
810        }
811    )*}
812}
813
814macro_rules! no_arg_builder {
815    ($($op:ident)*) => {
816        $(
817            pub fn $op(mut self) -> Self {
818                self.lst.add($op());
819                self
820            }
821        )*
822    }
823}
824
825macro_rules! math_op_r8_builder {
826    ($($reg:ident)*) => {$(
827        paste::paste! {
828
829            pub fn [<add_ $reg:lower>] (mut self) -> Self {
830                self.lst.add([<add_ $reg:lower>] () );
831                self
832            }
833
834            pub fn [<sub_ $reg:lower>] (mut self) -> Self {
835                self.lst.add([<add_ $reg:lower>] () );
836                self
837            }
838        }
839    )*}
840}
841
842impl ListingBuilder {
843    ld_r8_expr_builder! {a b c d e h l}
844
845    ld_r16_expr_builder! {af bc de hl}
846
847    ld_mem_r16_builder! {bc de}
848
849    ld_mem_hl_r8_builder! {A B C D E H L}
850
851    no_arg_builder! {exx nop ldi ldd ldir lddr neg exa ex_hl_de halt di ei ind indr outd outdr outi outir ret}
852
853    ld_r8_r8_builder! {
854        A,A A,B A,C A,D A,E A,H A,L
855        B,A B,B B,C B,D B,E B,H B,L
856        C,A C,B C,C C,D C,E C,H C,L
857        D,A D,B D,C D,D D,E D,H D,L
858        E,A E,B E,C E,D E,E E,H E,L
859        H,A H,B H,C H,D H,E H,H H,L
860        L,A L,B L,C L,D L,E L,H L,L
861    }
862
863    math_op_r8_builder! { A B C D E H L}
864
865    pub fn ld_mem_hl_expr<E: Into<Expr>>(mut self, e: E) -> Self {
866        self.lst.add(ld_mem_hl_expr(e));
867        self
868    }
869
870    pub fn ld_mem_hl_r8<R: Into<Register8>>(mut self, r: R) -> Self {
871        self.lst.add(ld_mem_hl_r8(r.into()));
872        self
873    }
874
875    pub fn ld_r8_expr<R: Into<Register8>, E: Into<Expr>>(mut self, r: R, e: E) -> Self {
876        self.lst.add(ld_r8_expr(r, e));
877        self
878    }
879
880    pub fn ld_r16_expr<R: Into<Register16>, E: Into<Expr>>(mut self, r: R, e: E) -> Self {
881        self.lst.add(ld_r16_expr(r, e));
882        self
883    }
884
885    pub fn call<S: Into<SmolStr>>(self, label: S) -> Self {
886        self.call_expr(Expr::Label(label.into()))
887    }
888
889    pub fn call_expr<E: Into<Expr>>(mut self, expr: E) -> Self {
890        self.lst.add(call_expr(expr));
891        self
892    }
893
894    pub fn or_expr<E: Into<Expr>>(mut self, expr: E) -> Self {
895        let e = expr.into();
896        self.lst
897            .add(token_for_opcode_one_arg(Mnemonic::Or, e.into()));
898        self
899    }
900
901    pub fn xor_expr<E: Into<Expr>>(mut self, expr: E) -> Self {
902        let e = expr.into();
903        self.lst
904            .add(token_for_opcode_one_arg(Mnemonic::Xor, e.into()));
905        self
906    }
907
908    pub fn and_expr<E: Into<Expr>>(mut self, expr: E) -> Self {
909        let e = expr.into();
910        self.lst
911            .add(token_for_opcode_one_arg(Mnemonic::And, e.into()));
912        self
913    }
914
915    pub fn or_r8(mut self, r: Register8) -> Self {
916        self.lst
917            .add(token_for_opcode_one_arg(Mnemonic::Or, r.into()));
918        self
919    }
920
921    pub fn xor_r8(mut self, r: Register8) -> Self {
922        self.lst
923            .add(token_for_opcode_one_arg(Mnemonic::Xor, r.into()));
924        self
925    }
926
927    pub fn and_r8(mut self, r: Register8) -> Self {
928        self.lst
929            .add(token_for_opcode_one_arg(Mnemonic::And, r.into()));
930        self
931    }
932
933    pub fn comment<S: Into<String>>(mut self, comment: S) -> Self {
934        self.lst.add_comment(comment);
935        self
936    }
937
938    pub fn extend(mut self, other: Listing) -> Self {
939        self.lst.inject_listing(&other);
940        self
941    }
942
943    /// Add a repeating code THAT DOES NOT use the counter
944    pub fn repeat<L: Into<Listing>>(mut self, count: i32, code: L) -> Self {
945        let test = Expr::Value(count);
946        let rpt = Token::Repeat(test, code.into(), None, None);
947        self.lst.add(rpt);
948        self
949    }
950
951    pub fn build(self) -> Listing {
952        self.lst
953    }
954}
955
956/// Code function that generate Listing instead of Tokens
957pub mod routines {
958    use crate::builder::*;
959    use crate::tokens::tokens::Listing;
960
961    /// Generate the listing that handle a wait loop
962    /// Idea comes from Rhino/Batman Group http://cpcrulez.fr/forum/viewtopic.php?p=15827#p15827
963
964    #[allow(dead_code)]
965    pub fn wait(mut duration: u32) -> Listing {
966        let wait_code_for = |l_duration| {
967            assert!(l_duration > 0);
968            let loops = (l_duration - 1) / 4;
969            let loopsx4 = loops * 4;
970            let nops = l_duration - loopsx4 - 1;
971
972            let mut listing = Listing::default();
973            if loops != 0 {
974                listing.push(ld_b_expr(loops));
975                listing.push(djnz_expr("$"));
976            }
977
978            listing.push(defs_expr_expr(nops, 0));
979            listing
980        };
981
982        let mut full_code = Listing::new();
983        while duration > 1024 {
984            full_code.inject_listing(&wait_code_for(1024));
985            duration -= 1024;
986        }
987        if duration != 0 {
988            full_code.inject_listing(&wait_code_for(duration));
989        }
990
991        full_code
992    }
993}
994
995#[cfg(test)]
996mod tests {
997
998    #[test]
999    fn test_ld_r16() {
1000        use super::*;
1001        // just check if it compiles
1002        ld_af_expr(0);
1003    }
1004}