pulley_interpreter/interp/
debug.rs

1//! Primitive support for debugging Pulley
2//!
3//! This `Debug` visitor defined in this module is what's actually used as part
4//! of the interpreter loop in Pulley. Due to the code size impact of always
5//! including this and the runtime overhead of always checking a flag this is
6//! enabled/disabled via a `const DEBUG` below. This is currently only really
7//! suitable for one-off debugging while developing locally.
8//!
9//! The hope is that this'll eventually evolve into something more useful, but
10//! for now it's a quick-and-easy way to dump all the instructions that are
11//! executed as well as the values in various registers.
12//!
13//! If debugging is disabled, or in `#[no_std]` mode, then this module should
14//! compile away (e.g. a "zero cost abstraction").
15
16use super::Interpreter;
17use crate::decode::{ExtendedOpVisitor, OpVisitor};
18use crate::imms::*;
19use crate::regs::*;
20use alloc::string::ToString;
21
22// Whether or not debugging is enabled at all.
23const DEBUG: bool = false;
24
25// Whether or not these registers are dumped between each instruction.
26const DEBUG_X_REGS: bool = true;
27const DEBUG_F_REGS: bool = false;
28
29#[cfg(not(feature = "std"))]
30macro_rules! print {
31    ($($t:tt)*) => ({ let _ = format_args!($($t)*); })
32}
33#[cfg(not(feature = "std"))]
34macro_rules! println {
35    () => ();
36    ($($t:tt)*) => ({ let _ = format_args!($($t)*); })
37}
38
39#[repr(transparent)]
40pub(super) struct Debug<'a>(pub Interpreter<'a>);
41
42macro_rules! debug_then_delegate {
43    (
44        $(
45            $( #[$attr:meta] )*
46                $snake_name:ident = $name:ident $( {
47                $(
48                    $( #[$field_attr:meta] )*
49                    $field:ident : $field_ty:ty
50                ),*
51            } )? ;
52        )*
53    ) => {
54        $(
55            $( #[$attr] )*
56            fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return {
57                if DEBUG {
58                    println!(
59                        concat!(
60                            stringify!($snake_name),
61                            $(
62                                $(
63                                    " ",
64                                    stringify!($field),
65                                    "={:?}",
66                                )*
67                            )?
68                        ),
69                        $($($field),*)?
70                    );
71                }
72                self.0.$snake_name($( $($field),* )?)
73            }
74        )*
75    }
76}
77
78impl<'a> OpVisitor for Debug<'a> {
79    type BytecodeStream = <Interpreter<'a> as OpVisitor>::BytecodeStream;
80    type Return = <Interpreter<'a> as OpVisitor>::Return;
81
82    fn bytecode(&mut self) -> &mut Self::BytecodeStream {
83        self.0.bytecode()
84    }
85
86    fn before_visit(&mut self) {
87        self.0.record_executing_pc_for_profiling();
88        if !DEBUG {
89            return;
90        }
91        print!("\t{:?}\t", self.bytecode().as_ptr());
92    }
93
94    fn after_visit(&mut self) {
95        if !DEBUG {
96            return;
97        }
98        if DEBUG_X_REGS {
99            for (i, regs) in self.0.state.x_regs.chunks(4).enumerate() {
100                print!("\t\t");
101                for (j, reg) in regs.iter().enumerate() {
102                    let n = i * 4 + j;
103                    let val = reg.get_u64();
104                    let reg = XReg::new(n as u8).unwrap().to_string();
105                    print!(" {reg:>3}={val:#018x}");
106                }
107                println!();
108            }
109        }
110        if DEBUG_F_REGS {
111            for (i, regs) in self.0.state.f_regs.chunks(4).enumerate() {
112                print!("\t\t");
113                for (j, reg) in regs.iter().enumerate() {
114                    let n = i * 4 + j;
115                    let val = reg.get_f64().to_bits();
116                    let reg = FReg::new(n as u8).unwrap().to_string();
117                    print!(" {reg:>3}={val:#018x}");
118                }
119                println!();
120            }
121        }
122    }
123
124    for_each_op!(debug_then_delegate);
125}
126
127impl<'a> ExtendedOpVisitor for Debug<'a> {
128    for_each_extended_op!(debug_then_delegate);
129}