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 16 use super::Interpreter; 17 use crate::decode::{ExtendedOpVisitor, OpVisitor}; 18 use crate::imms::*; 19 use crate::regs::*; 20 use alloc::string::ToString; 21 22 // Whether or not debugging is enabled at all. 23 const DEBUG: bool = false; 24 25 // Whether or not these registers are dumped between each instruction. 26 const DEBUG_X_REGS: bool = true; 27 const DEBUG_F_REGS: bool = false; 28 29 #[cfg(not(feature = "std"))] 30 macro_rules! print { 31 ($($t:tt)*) => ({ let _ = format_args!($($t)*); }) 32 } 33 #[cfg(not(feature = "std"))] 34 macro_rules! println { 35 () => (); 36 ($($t:tt)*) => ({ let _ = format_args!($($t)*); }) 37 } 38 39 #[repr(transparent)] 40 pub(super) struct Debug<'a>(pub Interpreter<'a>); 41 42 macro_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 78 impl<'a> OpVisitor for Debug<'a> { 79 type BytecodeStream = <Interpreter<'a> as OpVisitor>::BytecodeStream; 80 type Return = <Interpreter<'a> as OpVisitor>::Return; 81 bytecode(&mut self) -> &mut Self::BytecodeStream82 fn bytecode(&mut self) -> &mut Self::BytecodeStream { 83 self.0.bytecode() 84 } 85 before_visit(&mut self)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 after_visit(&mut self)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 127 impl<'a> ExtendedOpVisitor for Debug<'a> { 128 for_each_extended_op!(debug_then_delegate); 129 } 130