@@ -20,7 +20,7 @@ const fn ret(flags: u8) -> bool {
2020pub const DEV_SIZE : usize = 16 ;
2121
2222/// Simple circular stack, with room for 256 items
23- #[ derive( Debug ) ]
23+ #[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
2424pub struct Stack {
2525 data : [ u8 ; 256 ] ,
2626
@@ -147,17 +147,17 @@ impl Value {
147147 }
148148 }
149149 #[ inline]
150- fn wrapping_shr ( & self , i : u32 ) -> Self {
150+ fn shr ( & self , i : u32 ) -> Self {
151151 match self {
152- Value :: Short ( v) => Value :: Short ( v. wrapping_shr ( i ) ) ,
153- Value :: Byte ( v) => Value :: Byte ( v. wrapping_shr ( i ) ) ,
152+ Value :: Short ( v) => Value :: Short ( v. checked_shr ( i ) . unwrap_or ( 0 ) ) ,
153+ Value :: Byte ( v) => Value :: Byte ( v. checked_shr ( i ) . unwrap_or ( 0 ) ) ,
154154 }
155155 }
156156 #[ inline]
157- fn wrapping_shl ( & self , i : u32 ) -> Self {
157+ fn shl ( & self , i : u32 ) -> Self {
158158 match self {
159- Value :: Short ( v) => Value :: Short ( v. wrapping_shl ( i ) ) ,
160- Value :: Byte ( v) => Value :: Byte ( v. wrapping_shl ( i ) ) ,
159+ Value :: Short ( v) => Value :: Short ( v. checked_shl ( i ) . unwrap_or ( 0 ) ) ,
160+ Value :: Byte ( v) => Value :: Byte ( v. checked_shl ( i ) . unwrap_or ( 0 ) ) ,
161161 }
162162 }
163163}
@@ -400,21 +400,45 @@ impl<'a> Uxn<'a> {
400400 #[ inline]
401401 pub fn run < D : Device > ( & mut self , dev : & mut D , mut pc : u16 ) -> u16 {
402402 match self . backend {
403- Backend :: Interpreter => {
404- loop {
405- let op = self . next ( & mut pc) ;
406- let Some ( next) = self . op ( op, dev, pc) else {
407- break ;
408- } ;
409- pc = next;
410- }
411- pc
412- }
403+ Backend :: Interpreter => loop {
404+ let op = self . next ( & mut pc) ;
405+ let Some ( next) = self . op ( op, dev, pc) else {
406+ break pc;
407+ } ;
408+ pc = next;
409+ } ,
413410 #[ cfg( feature = "native" ) ]
414411 Backend :: Native => native:: entry ( self , dev, pc) ,
415412 }
416413 }
417414
415+ /// Runs until the program terminates or we hit a stop condition
416+ ///
417+ /// Returns the new program counter if the program terminated, or `None` if
418+ /// the stop condition was reached.
419+ ///
420+ /// This function always uses the interpreter, ignoring
421+ /// [`self.backend`](Self::backend).
422+ #[ inline]
423+ pub fn run_until < D : Device , F : Fn ( & Self , & D , usize ) -> bool > (
424+ & mut self ,
425+ dev : & mut D ,
426+ mut pc : u16 ,
427+ stop : F ,
428+ ) -> Option < u16 > {
429+ for i in 0 .. {
430+ let op = self . next ( & mut pc) ;
431+ let Some ( next) = self . op ( op, dev, pc) else {
432+ return Some ( pc) ;
433+ } ;
434+ pc = next;
435+ if stop ( self , dev, i) {
436+ return None ;
437+ }
438+ }
439+ unreachable ! ( )
440+ }
441+
418442 /// Converts raw ports memory into a [`Ports`] object
419443 #[ inline]
420444 pub fn dev < D : Ports > ( & self ) -> & D {
@@ -1638,7 +1662,7 @@ impl<'a> Uxn<'a> {
16381662 let shr = u32:: from ( shift & 0xF ) ;
16391663 let shl = u32:: from ( shift >> 4 ) ;
16401664 let v = s. pop ( ) ;
1641- s. push ( v. wrapping_shr ( shr) . wrapping_shl ( shl) ) ;
1665+ s. push ( v. shr ( shr) . shl ( shl) ) ;
16421666 Some ( pc)
16431667 }
16441668}
@@ -1728,9 +1752,9 @@ pub use ram::UxnRam;
17281752
17291753////////////////////////////////////////////////////////////////////////////////
17301754
1731- # [ cfg ( test ) ]
1732- #[ allow( unused , non_upper_case_globals ) ]
1733- mod op {
1755+ /// Opcode names and constants
1756+ #[ allow( non_upper_case_globals , missing_docs ) ]
1757+ pub mod op {
17341758 pub const BRK : u8 = 0x0 ;
17351759 pub const INC : u8 = 0x1 ;
17361760 pub const POP : u8 = 0x2 ;
0 commit comments