feo3boy_opcodes/
gbz80types.rs

1//! Types which are used in the gbz80.
2use bitflags::bitflags;
3use proc_macro2::TokenStream;
4use quote::quote;
5
6use crate::compiler::args::{CrateFetcher, Literal};
7use crate::compiler::instr::builder::{InstrBuilder, MicrocodeReadable, MicrocodeWritable};
8use crate::microcode::Microcode;
9
10bitflags! {
11    /// Flags set after various operations.
12    #[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Hash)]
13    pub struct Flags: u8 {
14        /// result was zero.
15        const ZERO = 0x80;
16        /// operation was a subtraction.
17        const SUB = 0x40;
18        /// there was a carry in the middle of the number (bit 4 -> 5 for u8, uncertain which bits
19        /// this is for in u16).
20        const HALFCARRY = 0x20;
21        /// there was a carry out of the top of the number (bit 7 -> carry for u8, presumably bit 15
22        /// -> carry for u16, though not sure).
23        const CARRY = 0x10;
24    }
25}
26
27impl Flags {
28    /// Merge the given flags into the current flags by applying the given mask to set
29    /// only flags in that mask.
30    pub fn merge(&mut self, flags: Flags, mask: Flags) {
31        *self = (*self & !mask) | (flags & mask);
32    }
33
34    /// If the value is zero, returns `Flags::ZERO`, otherwise returns `Flags::empty()`.
35    pub fn check_zero(val: u8) -> Flags {
36        if val == 0 {
37            Flags::ZERO
38        } else {
39            Flags::empty()
40        }
41    }
42
43    /// If carry is true, returns `Flags::CARRY` otherwise returns `Flags::empty()`.
44    pub fn check_carry(carry: bool) -> Flags {
45        if carry {
46            Flags::CARRY
47        } else {
48            Flags::empty()
49        }
50    }
51}
52
53/// When used as a MicrocodeWritable, Flags causes a write to the Flags register which
54/// applies the given mask to the set of flags being written. In effect it is an
55/// instruction to overwrite the specified flags.
56impl MicrocodeWritable for Flags {
57    fn to_write(self) -> InstrBuilder {
58        Microcode::SetFlagsMasked { mask: self }.into()
59    }
60}
61
62/// When used as a MicrocodeReadable, Flags causes a read from the Flags register which
63/// applies the given mask to the set of flags being read. In effect it is an
64/// instruction to read just the specified flags and put zeroes for all others.
65impl MicrocodeReadable for Flags {
66    fn to_read(self) -> InstrBuilder {
67        Microcode::GetFlagsMasked { mask: self }.into()
68    }
69}
70
71impl Literal for Flags {
72    fn constant_value(&self, crates: CrateFetcher) -> TokenStream {
73        let feo3boy_opcodes = crates("feo3boy-opcodes");
74        let val = format!("0b{:b}u8", self.bits())
75            .parse::<proc_macro2::Literal>()
76            .unwrap();
77        quote! { #feo3boy_opcodes::gbz80types::Flags::from_bits_retain(#val) }.into()
78    }
79}