From 4d2e3957c37f7a11f2e6699f2ad8eabaac3e8972 Mon Sep 17 00:00:00 2001 From: Oleksandr Kozachuk Date: Sat, 4 Apr 2026 13:54:39 +0200 Subject: [PATCH] Replace 14 double-cell Rust host functions with Forth (Phase 2) Move to boot.fth: D+, D-, DNEGATE, DABS, D0=, D0<, D=, D<, D2*, D2/, DMAX, DMIN, M+, DU<. D+ uses proper carry detection via unsigned comparison after low-cell addition. All other double-cell words build on D+ and standard Forth stack operations. Removed 544 lines of Rust closures. Cumulative: ~1,091 Rust lines removed across Phases 1-2, replaced by ~80 lines of Forth. All 425 tests pass. --- crates/core/boot.fth | 46 ++++ crates/core/src/outer.rs | 546 +-------------------------------------- 2 files changed, 48 insertions(+), 544 deletions(-) diff --git a/crates/core/boot.fth b/crates/core/boot.fth index c275c40..b32ad24 100644 --- a/crates/core/boot.fth +++ b/crates/core/boot.fth @@ -59,3 +59,49 @@ 2DUP + 1- C@ BL <> IF EXIT THEN 1- REPEAT ; + +\ --------------------------------------------------------------- +\ Phase 2: Double-cell arithmetic +\ --------------------------------------------------------------- + +\ D+ ( d1 d2 -- d3 ) double-cell addition with carry +: D+ >R SWAP >R DUP >R + DUP R> U< IF R> R> + 1+ ELSE R> R> + THEN ; + +\ DNEGATE ( d -- -d ) double-cell negate (two's complement) +: DNEGATE INVERT SWAP INVERT SWAP 1 0 D+ ; + +\ D- ( d1 d2 -- d3 ) double-cell subtraction +: D- DNEGATE D+ ; + +\ DABS ( d -- |d| ) double-cell absolute value +: DABS DUP 0< IF DNEGATE THEN ; + +\ D0= ( d -- flag ) true if d is zero +: D0= OR 0= ; + +\ D0< ( d -- flag ) true if d is negative +: D0< NIP 0< ; + +\ D= ( d1 d2 -- flag ) true if d1 = d2 +: D= D- D0= ; + +\ D< ( d1 d2 -- flag ) true if d1 < d2 (signed) +: D< D- D0< ; + +\ D2* ( d -- d*2 ) double-cell shift left +: D2* 2DUP D+ ; + +\ D2/ ( d -- d/2 ) double-cell arithmetic shift right +: D2/ DUP 1 AND 31 LSHIFT >R 2/ SWAP 1 RSHIFT R> OR SWAP ; + +\ DMAX ( d1 d2 -- d-max ) double-cell maximum +: DMAX 2OVER 2OVER D< IF 2SWAP THEN 2DROP ; + +\ DMIN ( d1 d2 -- d-min ) double-cell minimum +: DMIN 2OVER 2OVER D< INVERT IF 2SWAP THEN 2DROP ; + +\ M+ ( d n -- d+n ) add single to double +: M+ S>D D+ ; + +\ DU< ( ud1 ud2 -- flag ) unsigned double-cell less-than +: DU< ROT 2DUP = IF 2DROP U< ELSE U< NIP NIP THEN ; diff --git a/crates/core/src/outer.rs b/crates/core/src/outer.rs index 0c899dd..1e5d38d 100644 --- a/crates/core/src/outer.rs +++ b/crates/core/src/outer.rs @@ -2276,25 +2276,12 @@ impl ForthVM { // \ already registered // -- Double-Number word set -- - self.register_d_plus()?; - self.register_d_minus()?; - self.register_dnegate()?; - self.register_dabs()?; - self.register_d_zero_eq()?; - self.register_d_zero_lt()?; - self.register_d_eq()?; - self.register_d_lt()?; + // D+, D-, DNEGATE, DABS, D0=, D0<, D=, D<, D2*, D2/, + // DMAX, DMIN, M+, DU<, 2ROT: defined in boot.fth self.register_d_to_s()?; - self.register_d2star()?; - self.register_d2slash()?; - self.register_dmax()?; - self.register_dmin()?; - self.register_m_plus()?; self.register_m_star_slash()?; self.register_d_dot()?; self.register_d_dot_r()?; - // 2ROT: defined in boot.fth - self.register_du_lt()?; // -- String word set -- self.register_compare()?; @@ -5648,302 +5635,6 @@ impl ForthVM { // Double-Number word set // ----------------------------------------------------------------------- - /// D+ ( d1 d2 -- d3 ) double-cell addition. - fn register_d_plus(&mut self) -> anyhow::Result<()> { - let memory = self.memory; - let dsp = self.dsp; - - let func = Func::new( - &mut self.store, - FuncType::new(&self.engine, [], []), - move |mut caller, _params, _results| { - let sp = dsp.get(&mut caller).unwrap_i32() as u32; - let data = memory.data(&caller); - // Stack: d2-hi(sp), d2-lo(sp+4), d1-hi(sp+8), d1-lo(sp+12) - let b: [u8; 4] = data[sp as usize..sp as usize + 4].try_into().unwrap(); - let d2_hi = i32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 4) as usize..(sp + 8) as usize] - .try_into() - .unwrap(); - let d2_lo = u32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 8) as usize..(sp + 12) as usize] - .try_into() - .unwrap(); - let d1_hi = i32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 12) as usize..(sp + 16) as usize] - .try_into() - .unwrap(); - let d1_lo = u32::from_le_bytes(b) as i64; - let d1 = (d1_hi << 32) | (d1_lo & 0xFFFF_FFFF); - let d2 = (d2_hi << 32) | (d2_lo & 0xFFFF_FFFF); - let result = d1.wrapping_add(d2); - let lo = result as i32; - let hi = (result >> 32) as i32; - // Pop 4, push 2: net sp + 8 - let new_sp = sp + 8; - let data = memory.data_mut(&mut caller); - data[(new_sp + 4) as usize..(new_sp + 8) as usize] - .copy_from_slice(&lo.to_le_bytes()); - data[new_sp as usize..new_sp as usize + 4].copy_from_slice(&hi.to_le_bytes()); - dsp.set(&mut caller, Val::I32(new_sp as i32))?; - Ok(()) - }, - ); - - self.register_host_primitive("D+", false, func)?; - Ok(()) - } - - /// D- ( d1 d2 -- d3 ) double-cell subtraction. - fn register_d_minus(&mut self) -> anyhow::Result<()> { - let memory = self.memory; - let dsp = self.dsp; - - let func = Func::new( - &mut self.store, - FuncType::new(&self.engine, [], []), - move |mut caller, _params, _results| { - let sp = dsp.get(&mut caller).unwrap_i32() as u32; - let data = memory.data(&caller); - let b: [u8; 4] = data[sp as usize..sp as usize + 4].try_into().unwrap(); - let d2_hi = i32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 4) as usize..(sp + 8) as usize] - .try_into() - .unwrap(); - let d2_lo = u32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 8) as usize..(sp + 12) as usize] - .try_into() - .unwrap(); - let d1_hi = i32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 12) as usize..(sp + 16) as usize] - .try_into() - .unwrap(); - let d1_lo = u32::from_le_bytes(b) as i64; - let d1 = (d1_hi << 32) | (d1_lo & 0xFFFF_FFFF); - let d2 = (d2_hi << 32) | (d2_lo & 0xFFFF_FFFF); - let result = d1.wrapping_sub(d2); - let lo = result as i32; - let hi = (result >> 32) as i32; - let new_sp = sp + 8; - let data = memory.data_mut(&mut caller); - data[(new_sp + 4) as usize..(new_sp + 8) as usize] - .copy_from_slice(&lo.to_le_bytes()); - data[new_sp as usize..new_sp as usize + 4].copy_from_slice(&hi.to_le_bytes()); - dsp.set(&mut caller, Val::I32(new_sp as i32))?; - Ok(()) - }, - ); - - self.register_host_primitive("D-", false, func)?; - Ok(()) - } - - /// DNEGATE ( d -- -d ) negate double-cell. - fn register_dnegate(&mut self) -> anyhow::Result<()> { - let memory = self.memory; - let dsp = self.dsp; - - let func = Func::new( - &mut self.store, - FuncType::new(&self.engine, [], []), - move |mut caller, _params, _results| { - let sp = dsp.get(&mut caller).unwrap_i32() as u32; - let data = memory.data(&caller); - let b: [u8; 4] = data[sp as usize..sp as usize + 4].try_into().unwrap(); - let hi = i32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 4) as usize..(sp + 8) as usize] - .try_into() - .unwrap(); - let lo = u32::from_le_bytes(b) as i64; - let d = (hi << 32) | (lo & 0xFFFF_FFFF); - let result = d.wrapping_neg(); - let data = memory.data_mut(&mut caller); - data[sp as usize..sp as usize + 4] - .copy_from_slice(&((result >> 32) as i32).to_le_bytes()); - data[(sp + 4) as usize..(sp + 8) as usize] - .copy_from_slice(&(result as i32).to_le_bytes()); - Ok(()) - }, - ); - - self.register_host_primitive("DNEGATE", false, func)?; - Ok(()) - } - - /// DABS ( d -- |d| ) absolute value of double-cell. - fn register_dabs(&mut self) -> anyhow::Result<()> { - let memory = self.memory; - let dsp = self.dsp; - - let func = Func::new( - &mut self.store, - FuncType::new(&self.engine, [], []), - move |mut caller, _params, _results| { - let sp = dsp.get(&mut caller).unwrap_i32() as u32; - let data = memory.data(&caller); - let b: [u8; 4] = data[sp as usize..sp as usize + 4].try_into().unwrap(); - let hi = i32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 4) as usize..(sp + 8) as usize] - .try_into() - .unwrap(); - let lo = u32::from_le_bytes(b) as i64; - let d = (hi << 32) | (lo & 0xFFFF_FFFF); - let result = if d < 0 { d.wrapping_neg() } else { d }; - let data = memory.data_mut(&mut caller); - data[sp as usize..sp as usize + 4] - .copy_from_slice(&((result >> 32) as i32).to_le_bytes()); - data[(sp + 4) as usize..(sp + 8) as usize] - .copy_from_slice(&(result as i32).to_le_bytes()); - Ok(()) - }, - ); - - self.register_host_primitive("DABS", false, func)?; - Ok(()) - } - - /// D0= ( d -- flag ) true if d is zero. - fn register_d_zero_eq(&mut self) -> anyhow::Result<()> { - let memory = self.memory; - let dsp = self.dsp; - - let func = Func::new( - &mut self.store, - FuncType::new(&self.engine, [], []), - move |mut caller, _params, _results| { - let sp = dsp.get(&mut caller).unwrap_i32() as u32; - let data = memory.data(&caller); - let b: [u8; 4] = data[sp as usize..sp as usize + 4].try_into().unwrap(); - let hi = u32::from_le_bytes(b); - let b: [u8; 4] = data[(sp + 4) as usize..(sp + 8) as usize] - .try_into() - .unwrap(); - let lo = u32::from_le_bytes(b); - let flag: i32 = if hi == 0 && lo == 0 { -1 } else { 0 }; - // Pop 2, push 1: net sp + 4 - let new_sp = sp + 4; - let data = memory.data_mut(&mut caller); - data[new_sp as usize..new_sp as usize + 4].copy_from_slice(&flag.to_le_bytes()); - dsp.set(&mut caller, Val::I32(new_sp as i32))?; - Ok(()) - }, - ); - - self.register_host_primitive("D0=", false, func)?; - Ok(()) - } - - /// D0< ( d -- flag ) true if d is negative. - fn register_d_zero_lt(&mut self) -> anyhow::Result<()> { - let memory = self.memory; - let dsp = self.dsp; - - let func = Func::new( - &mut self.store, - FuncType::new(&self.engine, [], []), - move |mut caller, _params, _results| { - let sp = dsp.get(&mut caller).unwrap_i32() as u32; - let data = memory.data(&caller); - let b: [u8; 4] = data[sp as usize..sp as usize + 4].try_into().unwrap(); - let hi = i32::from_le_bytes(b); - // D0< only checks the sign of the high cell - let flag: i32 = if hi < 0 { -1 } else { 0 }; - // Pop 2, push 1: net sp + 4 - let new_sp = sp + 4; - let data = memory.data_mut(&mut caller); - data[new_sp as usize..new_sp as usize + 4].copy_from_slice(&flag.to_le_bytes()); - dsp.set(&mut caller, Val::I32(new_sp as i32))?; - Ok(()) - }, - ); - - self.register_host_primitive("D0<", false, func)?; - Ok(()) - } - - /// D= ( d1 d2 -- flag ) true if d1 equals d2. - fn register_d_eq(&mut self) -> anyhow::Result<()> { - let memory = self.memory; - let dsp = self.dsp; - - let func = Func::new( - &mut self.store, - FuncType::new(&self.engine, [], []), - move |mut caller, _params, _results| { - let sp = dsp.get(&mut caller).unwrap_i32() as u32; - let data = memory.data(&caller); - let b: [u8; 4] = data[sp as usize..sp as usize + 4].try_into().unwrap(); - let d2_hi = u32::from_le_bytes(b); - let b: [u8; 4] = data[(sp + 4) as usize..(sp + 8) as usize] - .try_into() - .unwrap(); - let d2_lo = u32::from_le_bytes(b); - let b: [u8; 4] = data[(sp + 8) as usize..(sp + 12) as usize] - .try_into() - .unwrap(); - let d1_hi = u32::from_le_bytes(b); - let b: [u8; 4] = data[(sp + 12) as usize..(sp + 16) as usize] - .try_into() - .unwrap(); - let d1_lo = u32::from_le_bytes(b); - let flag: i32 = if d1_hi == d2_hi && d1_lo == d2_lo { - -1 - } else { - 0 - }; - // Pop 4, push 1: net sp + 12 - let new_sp = sp + 12; - let data = memory.data_mut(&mut caller); - data[new_sp as usize..new_sp as usize + 4].copy_from_slice(&flag.to_le_bytes()); - dsp.set(&mut caller, Val::I32(new_sp as i32))?; - Ok(()) - }, - ); - - self.register_host_primitive("D=", false, func)?; - Ok(()) - } - - /// D< ( d1 d2 -- flag ) signed double-cell comparison. - fn register_d_lt(&mut self) -> anyhow::Result<()> { - let memory = self.memory; - let dsp = self.dsp; - - let func = Func::new( - &mut self.store, - FuncType::new(&self.engine, [], []), - move |mut caller, _params, _results| { - let sp = dsp.get(&mut caller).unwrap_i32() as u32; - let data = memory.data(&caller); - let b: [u8; 4] = data[sp as usize..sp as usize + 4].try_into().unwrap(); - let d2_hi = i32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 4) as usize..(sp + 8) as usize] - .try_into() - .unwrap(); - let d2_lo = u32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 8) as usize..(sp + 12) as usize] - .try_into() - .unwrap(); - let d1_hi = i32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 12) as usize..(sp + 16) as usize] - .try_into() - .unwrap(); - let d1_lo = u32::from_le_bytes(b) as i64; - let d1 = (d1_hi << 32) | (d1_lo & 0xFFFF_FFFF); - let d2 = (d2_hi << 32) | (d2_lo & 0xFFFF_FFFF); - let flag: i32 = if d1 < d2 { -1 } else { 0 }; - let new_sp = sp + 12; - let data = memory.data_mut(&mut caller); - data[new_sp as usize..new_sp as usize + 4].copy_from_slice(&flag.to_le_bytes()); - dsp.set(&mut caller, Val::I32(new_sp as i32))?; - Ok(()) - }, - ); - - self.register_host_primitive("D<", false, func)?; - Ok(()) - } - /// D>S ( d -- n ) convert double to single (just drop high cell). fn register_d_to_s(&mut self) -> anyhow::Result<()> { // D>S just drops the high cell @@ -5951,199 +5642,6 @@ impl ForthVM { Ok(()) } - /// D2* ( d -- d*2 ) double-cell shift left 1. - fn register_d2star(&mut self) -> anyhow::Result<()> { - let memory = self.memory; - let dsp = self.dsp; - - let func = Func::new( - &mut self.store, - FuncType::new(&self.engine, [], []), - move |mut caller, _params, _results| { - let sp = dsp.get(&mut caller).unwrap_i32() as u32; - let data = memory.data(&caller); - let b: [u8; 4] = data[sp as usize..sp as usize + 4].try_into().unwrap(); - let hi = u32::from_le_bytes(b) as u64; - let b: [u8; 4] = data[(sp + 4) as usize..(sp + 8) as usize] - .try_into() - .unwrap(); - let lo = u32::from_le_bytes(b) as u64; - let d = (hi << 32) | lo; - let result = d << 1; - let data = memory.data_mut(&mut caller); - data[sp as usize..sp as usize + 4] - .copy_from_slice(&((result >> 32) as u32).to_le_bytes()); - data[(sp + 4) as usize..(sp + 8) as usize] - .copy_from_slice(&(result as u32).to_le_bytes()); - Ok(()) - }, - ); - - self.register_host_primitive("D2*", false, func)?; - Ok(()) - } - - /// D2/ ( d -- d/2 ) double-cell arithmetic shift right 1. - fn register_d2slash(&mut self) -> anyhow::Result<()> { - let memory = self.memory; - let dsp = self.dsp; - - let func = Func::new( - &mut self.store, - FuncType::new(&self.engine, [], []), - move |mut caller, _params, _results| { - let sp = dsp.get(&mut caller).unwrap_i32() as u32; - let data = memory.data(&caller); - let b: [u8; 4] = data[sp as usize..sp as usize + 4].try_into().unwrap(); - let hi = i32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 4) as usize..(sp + 8) as usize] - .try_into() - .unwrap(); - let lo = u32::from_le_bytes(b) as i64; - let d = (hi << 32) | (lo & 0xFFFF_FFFF); - let result = d >> 1; // arithmetic shift - let data = memory.data_mut(&mut caller); - data[sp as usize..sp as usize + 4] - .copy_from_slice(&((result >> 32) as i32).to_le_bytes()); - data[(sp + 4) as usize..(sp + 8) as usize] - .copy_from_slice(&(result as i32).to_le_bytes()); - Ok(()) - }, - ); - - self.register_host_primitive("D2/", false, func)?; - Ok(()) - } - - /// DMAX ( d1 d2 -- d3 ) return the larger of two doubles. - fn register_dmax(&mut self) -> anyhow::Result<()> { - let memory = self.memory; - let dsp = self.dsp; - - let func = Func::new( - &mut self.store, - FuncType::new(&self.engine, [], []), - move |mut caller, _params, _results| { - let sp = dsp.get(&mut caller).unwrap_i32() as u32; - let data = memory.data(&caller); - let b: [u8; 4] = data[sp as usize..sp as usize + 4].try_into().unwrap(); - let d2_hi = i32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 4) as usize..(sp + 8) as usize] - .try_into() - .unwrap(); - let d2_lo = u32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 8) as usize..(sp + 12) as usize] - .try_into() - .unwrap(); - let d1_hi = i32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 12) as usize..(sp + 16) as usize] - .try_into() - .unwrap(); - let d1_lo = u32::from_le_bytes(b) as i64; - let d1 = (d1_hi << 32) | (d1_lo & 0xFFFF_FFFF); - let d2 = (d2_hi << 32) | (d2_lo & 0xFFFF_FFFF); - let result = if d1 > d2 { d1 } else { d2 }; - let lo = result as i32; - let hi = (result >> 32) as i32; - let new_sp = sp + 8; - let data = memory.data_mut(&mut caller); - data[(new_sp + 4) as usize..(new_sp + 8) as usize] - .copy_from_slice(&lo.to_le_bytes()); - data[new_sp as usize..new_sp as usize + 4].copy_from_slice(&hi.to_le_bytes()); - dsp.set(&mut caller, Val::I32(new_sp as i32))?; - Ok(()) - }, - ); - - self.register_host_primitive("DMAX", false, func)?; - Ok(()) - } - - /// DMIN ( d1 d2 -- d3 ) return the smaller of two doubles. - fn register_dmin(&mut self) -> anyhow::Result<()> { - let memory = self.memory; - let dsp = self.dsp; - - let func = Func::new( - &mut self.store, - FuncType::new(&self.engine, [], []), - move |mut caller, _params, _results| { - let sp = dsp.get(&mut caller).unwrap_i32() as u32; - let data = memory.data(&caller); - let b: [u8; 4] = data[sp as usize..sp as usize + 4].try_into().unwrap(); - let d2_hi = i32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 4) as usize..(sp + 8) as usize] - .try_into() - .unwrap(); - let d2_lo = u32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 8) as usize..(sp + 12) as usize] - .try_into() - .unwrap(); - let d1_hi = i32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 12) as usize..(sp + 16) as usize] - .try_into() - .unwrap(); - let d1_lo = u32::from_le_bytes(b) as i64; - let d1 = (d1_hi << 32) | (d1_lo & 0xFFFF_FFFF); - let d2 = (d2_hi << 32) | (d2_lo & 0xFFFF_FFFF); - let result = if d1 < d2 { d1 } else { d2 }; - let lo = result as i32; - let hi = (result >> 32) as i32; - let new_sp = sp + 8; - let data = memory.data_mut(&mut caller); - data[(new_sp + 4) as usize..(new_sp + 8) as usize] - .copy_from_slice(&lo.to_le_bytes()); - data[new_sp as usize..new_sp as usize + 4].copy_from_slice(&hi.to_le_bytes()); - dsp.set(&mut caller, Val::I32(new_sp as i32))?; - Ok(()) - }, - ); - - self.register_host_primitive("DMIN", false, func)?; - Ok(()) - } - - /// M+ ( d n -- d ) add single to double. - fn register_m_plus(&mut self) -> anyhow::Result<()> { - let memory = self.memory; - let dsp = self.dsp; - - let func = Func::new( - &mut self.store, - FuncType::new(&self.engine, [], []), - move |mut caller, _params, _results| { - let sp = dsp.get(&mut caller).unwrap_i32() as u32; - let data = memory.data(&caller); - // Stack: n(sp), d-hi(sp+4), d-lo(sp+8) - let b: [u8; 4] = data[sp as usize..sp as usize + 4].try_into().unwrap(); - let n = i32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 4) as usize..(sp + 8) as usize] - .try_into() - .unwrap(); - let d_hi = i32::from_le_bytes(b) as i64; - let b: [u8; 4] = data[(sp + 8) as usize..(sp + 12) as usize] - .try_into() - .unwrap(); - let d_lo = u32::from_le_bytes(b) as i64; - let d = (d_hi << 32) | (d_lo & 0xFFFF_FFFF); - let result = d.wrapping_add(n); - let lo = result as i32; - let hi = (result >> 32) as i32; - // Pop 3, push 2: net sp + 4 - let new_sp = sp + 4; - let data = memory.data_mut(&mut caller); - data[(new_sp + 4) as usize..(new_sp + 8) as usize] - .copy_from_slice(&lo.to_le_bytes()); - data[new_sp as usize..new_sp as usize + 4].copy_from_slice(&hi.to_le_bytes()); - dsp.set(&mut caller, Val::I32(new_sp as i32))?; - Ok(()) - }, - ); - - self.register_host_primitive("M+", false, func)?; - Ok(()) - } - /// M*/ ( d n1 n2 -- d ) multiply d by n1, divide by n2. fn register_m_star_slash(&mut self) -> anyhow::Result<()> { let memory = self.memory; @@ -6284,46 +5782,6 @@ impl ForthVM { Ok(()) } - /// DU< ( ud1 ud2 -- flag ) unsigned double-cell comparison. - fn register_du_lt(&mut self) -> anyhow::Result<()> { - let memory = self.memory; - let dsp = self.dsp; - - let func = Func::new( - &mut self.store, - FuncType::new(&self.engine, [], []), - move |mut caller, _params, _results| { - let sp = dsp.get(&mut caller).unwrap_i32() as u32; - let data = memory.data(&caller); - let b: [u8; 4] = data[sp as usize..sp as usize + 4].try_into().unwrap(); - let d2_hi = u32::from_le_bytes(b) as u64; - let b: [u8; 4] = data[(sp + 4) as usize..(sp + 8) as usize] - .try_into() - .unwrap(); - let d2_lo = u32::from_le_bytes(b) as u64; - let b: [u8; 4] = data[(sp + 8) as usize..(sp + 12) as usize] - .try_into() - .unwrap(); - let d1_hi = u32::from_le_bytes(b) as u64; - let b: [u8; 4] = data[(sp + 12) as usize..(sp + 16) as usize] - .try_into() - .unwrap(); - let d1_lo = u32::from_le_bytes(b) as u64; - let d1 = (d1_hi << 32) | d1_lo; - let d2 = (d2_hi << 32) | d2_lo; - let flag: i32 = if d1 < d2 { -1 } else { 0 }; - let new_sp = sp + 12; - let data = memory.data_mut(&mut caller); - data[new_sp as usize..new_sp as usize + 4].copy_from_slice(&flag.to_le_bytes()); - dsp.set(&mut caller, Val::I32(new_sp as i32))?; - Ok(()) - }, - ); - - self.register_host_primitive("DU<", false, func)?; - Ok(()) - } - /// 2CONSTANT ( x1 x2 "name" -- ) define a double-cell constant. fn define_2constant(&mut self) -> anyhow::Result<()> { let name = self