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}