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.
This commit is contained in:
@@ -59,3 +59,49 @@
|
|||||||
2DUP + 1- C@ BL <> IF EXIT THEN
|
2DUP + 1- C@ BL <> IF EXIT THEN
|
||||||
1-
|
1-
|
||||||
REPEAT ;
|
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 ;
|
||||||
|
|||||||
+2
-544
@@ -2276,25 +2276,12 @@ impl ForthVM {
|
|||||||
// \ already registered
|
// \ already registered
|
||||||
|
|
||||||
// -- Double-Number word set --
|
// -- Double-Number word set --
|
||||||
self.register_d_plus()?;
|
// D+, D-, DNEGATE, DABS, D0=, D0<, D=, D<, D2*, D2/,
|
||||||
self.register_d_minus()?;
|
// DMAX, DMIN, M+, DU<, 2ROT: defined in boot.fth
|
||||||
self.register_dnegate()?;
|
|
||||||
self.register_dabs()?;
|
|
||||||
self.register_d_zero_eq()?;
|
|
||||||
self.register_d_zero_lt()?;
|
|
||||||
self.register_d_eq()?;
|
|
||||||
self.register_d_lt()?;
|
|
||||||
self.register_d_to_s()?;
|
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_m_star_slash()?;
|
||||||
self.register_d_dot()?;
|
self.register_d_dot()?;
|
||||||
self.register_d_dot_r()?;
|
self.register_d_dot_r()?;
|
||||||
// 2ROT: defined in boot.fth
|
|
||||||
self.register_du_lt()?;
|
|
||||||
|
|
||||||
// -- String word set --
|
// -- String word set --
|
||||||
self.register_compare()?;
|
self.register_compare()?;
|
||||||
@@ -5648,302 +5635,6 @@ impl ForthVM {
|
|||||||
// Double-Number word set
|
// 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).
|
/// D>S ( d -- n ) convert double to single (just drop high cell).
|
||||||
fn register_d_to_s(&mut self) -> anyhow::Result<()> {
|
fn register_d_to_s(&mut self) -> anyhow::Result<()> {
|
||||||
// D>S just drops the high cell
|
// D>S just drops the high cell
|
||||||
@@ -5951,199 +5642,6 @@ impl ForthVM {
|
|||||||
Ok(())
|
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.
|
/// M*/ ( d n1 n2 -- d ) multiply d by n1, divide by n2.
|
||||||
fn register_m_star_slash(&mut self) -> anyhow::Result<()> {
|
fn register_m_star_slash(&mut self) -> anyhow::Result<()> {
|
||||||
let memory = self.memory;
|
let memory = self.memory;
|
||||||
@@ -6284,46 +5782,6 @@ impl ForthVM {
|
|||||||
Ok(())
|
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.
|
/// 2CONSTANT ( x1 x2 "name" -- ) define a double-cell constant.
|
||||||
fn define_2constant(&mut self) -> anyhow::Result<()> {
|
fn define_2constant(&mut self) -> anyhow::Result<()> {
|
||||||
let name = self
|
let name = self
|
||||||
|
|||||||
Reference in New Issue
Block a user