|
|
|
@ -1,9 +1,9 @@ |
|
|
|
|
use crate::run_thread::{ThreadToken, RunThread}; |
|
|
|
|
use asm::instr::{Op, Cond}; |
|
|
|
|
use crate::run_thread::{RunThread}; |
|
|
|
|
use asm::instr::{Op}; |
|
|
|
|
use crate::fault::Fault; |
|
|
|
|
use crate::frame::StackFrame; |
|
|
|
|
use asm::data::literal::{Value, is_positive, is_negative, Addr}; |
|
|
|
|
use std::ops::{Rem, BitXor, Shl}; |
|
|
|
|
use asm::data::literal::{Addr}; |
|
|
|
|
use std::ops::{Rem}; |
|
|
|
|
use num_traits::PrimInt; |
|
|
|
|
|
|
|
|
|
pub type CyclesSpent = usize; |
|
|
|
@ -38,12 +38,12 @@ impl RunThread { |
|
|
|
|
Op::Barrier(msg) => { |
|
|
|
|
return Err(Fault::Barrier { |
|
|
|
|
msg: msg.clone().unwrap_or_else(|| "No msg".into()) |
|
|
|
|
}) |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
Op::Fault(msg) => { |
|
|
|
|
return Err(Fault::FaultInstr { |
|
|
|
|
msg: msg.clone().unwrap_or_else(|| "No msg".into()) |
|
|
|
|
}) |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
Op::FarJump(name) => { |
|
|
|
|
debug!("Far jump to {}", name); |
|
|
|
@ -56,7 +56,7 @@ impl RunThread { |
|
|
|
|
return Err(e); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
Op::Call(name, args) => { |
|
|
|
|
debug!("Call routine {}", name); |
|
|
|
|
match self.program.find_routine(name) { |
|
|
|
@ -77,7 +77,7 @@ impl RunThread { |
|
|
|
|
return Err(e); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
Op::Ret(retvals) => { |
|
|
|
|
match self.call_stack.pop() { |
|
|
|
|
Some(previous) => { |
|
|
|
@ -93,7 +93,7 @@ impl RunThread { |
|
|
|
|
return Err(Fault::CallStackUnderflow); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
Op::Skip(val) => { |
|
|
|
|
let steps = frame.read(*val)?; |
|
|
|
|
advance = i64::from_ne_bytes(steps.to_ne_bytes()); |
|
|
|
@ -106,239 +106,193 @@ impl RunThread { |
|
|
|
|
self.program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + advance) as u64))?; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Op::Mov(dst, src) => { |
|
|
|
|
Op::Move { dst, src } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let val = frame.read(*src)?; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.status.update(val); |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
} |
|
|
|
|
Op::Cmp(a, b) => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let a = frame.read(*a)?; |
|
|
|
|
let b = frame.read(*b)?; |
|
|
|
|
frame.status.equal = a == b; |
|
|
|
|
frame.status.zero = a == 0 && b == 0; |
|
|
|
|
frame.status.lower = a < b; |
|
|
|
|
frame.status.greater = a > b; |
|
|
|
|
frame.status.positive = is_positive(a) && is_positive(b); |
|
|
|
|
frame.status.negative = is_negative(a) && is_negative(b); |
|
|
|
|
} |
|
|
|
|
Op::Inc(reg) => { |
|
|
|
|
Op::Test { a } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut val = frame.read(reg.as_rd())?; |
|
|
|
|
val = val.wrapping_add(1); |
|
|
|
|
frame.status.overflow = (val == 0); |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.write(*reg, val)?; |
|
|
|
|
let res = frame.read(*a)?; |
|
|
|
|
frame.status.update(res); |
|
|
|
|
} |
|
|
|
|
Op::Dec(reg) => { |
|
|
|
|
Op::Compare { a, b } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut val = frame.read(reg.as_rd())?; |
|
|
|
|
frame.status.overflow = (val == 0); // will overflow
|
|
|
|
|
val = val.wrapping_sub(1); |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.write(*reg, val)?; |
|
|
|
|
let x = frame.read(*a)?; |
|
|
|
|
let y = frame.read(*b)?; |
|
|
|
|
frame.status.equal = x == y; |
|
|
|
|
frame.status.lower = x < y; |
|
|
|
|
frame.status.greater = x > y; |
|
|
|
|
// Test flags are set when both arguments have the property
|
|
|
|
|
if x == y { |
|
|
|
|
frame.status.update(x); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Op::Add(dst, src) => { |
|
|
|
|
Op::Add { dst, a, b } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut a = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*src)?; |
|
|
|
|
let (val, ov) = if let Some(v) = a.checked_add(b) { |
|
|
|
|
let x = frame.read(*a)?; |
|
|
|
|
let y = frame.read(*b)?; |
|
|
|
|
let (res, ov) = if let Some(v) = x.checked_add(y) { |
|
|
|
|
(v, false) |
|
|
|
|
} else { |
|
|
|
|
(a.wrapping_add(b), true) |
|
|
|
|
(x.wrapping_add(y), true) |
|
|
|
|
}; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.status.update(res); |
|
|
|
|
frame.status.overflow = ov; |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
frame.write(*dst, res)?; |
|
|
|
|
} |
|
|
|
|
Op::Sub(dst, src) => { |
|
|
|
|
Op::Sub { dst, a, b } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut a = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*src)?; |
|
|
|
|
let (val, ov) = if let Some(v) = a.checked_sub(b) { |
|
|
|
|
let x = frame.read(*a)?; |
|
|
|
|
let y = frame.read(*b)?; |
|
|
|
|
let (res, ov) = if let Some(v) = x.checked_sub(y) { |
|
|
|
|
(v, false) |
|
|
|
|
} else { |
|
|
|
|
(a.wrapping_sub(b), true) |
|
|
|
|
(x.wrapping_sub(y), true) |
|
|
|
|
}; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.status.update(res); |
|
|
|
|
frame.status.overflow = ov; |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
frame.write(*dst, res)?; |
|
|
|
|
} |
|
|
|
|
Op::Mul(dst, src) => { |
|
|
|
|
Op::Mul { dst, a, b } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut a = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*src)?; |
|
|
|
|
let (val, ov) = if let Some(v) = a.checked_mul(b) { |
|
|
|
|
let x = frame.read(*a)?; |
|
|
|
|
let y = frame.read(*b)?; |
|
|
|
|
let (res, ov) = if let Some(v) = x.checked_mul(y) { |
|
|
|
|
(v, false) |
|
|
|
|
} else { |
|
|
|
|
(a.wrapping_mul(b), true) |
|
|
|
|
(x.wrapping_mul(y), true) |
|
|
|
|
}; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.status.update(res); |
|
|
|
|
frame.status.overflow = ov; |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
frame.write(*dst, res)?; |
|
|
|
|
} |
|
|
|
|
Op::Div(dst, src) => { |
|
|
|
|
Op::Div { dst, rem, a, div } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut a = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*src)?; |
|
|
|
|
if b == 0 { |
|
|
|
|
frame.status.overflow = true; |
|
|
|
|
// TODO ?
|
|
|
|
|
let x = frame.read(*a)?; |
|
|
|
|
let d = frame.read(*div)?; |
|
|
|
|
if d == 0 { |
|
|
|
|
frame.status.invalid = true; |
|
|
|
|
} else { |
|
|
|
|
let (val, ov) = if let Some(v) = a.checked_div(b) { |
|
|
|
|
(v, false) |
|
|
|
|
let (res, remainder, ov) = if let Some(v) = x.checked_div(d) { |
|
|
|
|
(v, x.rem(d), false) |
|
|
|
|
} else { |
|
|
|
|
(a.wrapping_div(b), true) |
|
|
|
|
(x.wrapping_div(d), x.wrapping_rem(d), true) |
|
|
|
|
}; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.status.update(res); |
|
|
|
|
frame.status.overflow = ov; |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
frame.write(*dst, res)?; |
|
|
|
|
frame.write(*rem, remainder)?; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Op::Mod(dst, src) => { |
|
|
|
|
Op::Mod { dst, a, div } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut a = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*src)?; |
|
|
|
|
if b == 0 { |
|
|
|
|
frame.status.overflow = true; |
|
|
|
|
// TODO ?
|
|
|
|
|
let x = frame.read(*a)?; |
|
|
|
|
let d = frame.read(*div)?; |
|
|
|
|
if d == 0 { |
|
|
|
|
frame.status.invalid = true; |
|
|
|
|
} else { |
|
|
|
|
let (val, ov) = if let Some(v) = a.checked_rem(b) { |
|
|
|
|
let (remainder, ov) = if let Some(v) = x.checked_rem(d) { |
|
|
|
|
(v, false) |
|
|
|
|
} else { |
|
|
|
|
(a.wrapping_rem(b), true) |
|
|
|
|
(x.wrapping_rem(d), true) |
|
|
|
|
}; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.status.update(remainder); |
|
|
|
|
frame.status.overflow = ov; |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
frame.write(*dst, remainder)?; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Op::DivRem(dst, remptr, src) => { |
|
|
|
|
Op::And { dst, a, b } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut a = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*src)?; |
|
|
|
|
if b == 0 { |
|
|
|
|
frame.status.overflow = true; |
|
|
|
|
// TODO ?
|
|
|
|
|
} else { |
|
|
|
|
let (val, rem, ov) = if let Some(v) = a.checked_div(b) { |
|
|
|
|
(v, a.rem(b), false) |
|
|
|
|
} else { |
|
|
|
|
(a.wrapping_div(b), a.wrapping_rem(b), true) |
|
|
|
|
}; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.status.overflow = ov; |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
frame.write(*remptr, rem)?; |
|
|
|
|
} |
|
|
|
|
let x = frame.read(*a)?; |
|
|
|
|
let y = frame.read(*b)?; |
|
|
|
|
let res = x & y; |
|
|
|
|
frame.status.update(res); |
|
|
|
|
frame.write(*dst, res)?; |
|
|
|
|
} |
|
|
|
|
Op::And(dst, src) => { |
|
|
|
|
Op::Or { dst, a, b } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut val = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*src)?; |
|
|
|
|
val &= b; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
let x = frame.read(*a)?; |
|
|
|
|
let y = frame.read(*b)?; |
|
|
|
|
let res = x | y; |
|
|
|
|
frame.status.update(res); |
|
|
|
|
frame.write(*dst, res)?; |
|
|
|
|
} |
|
|
|
|
Op::Or(dst, src) => { |
|
|
|
|
Op::Xor { dst, a, b } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut val = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*src)?; |
|
|
|
|
val |= b; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
let x = frame.read(*a)?; |
|
|
|
|
let y = frame.read(*b)?; |
|
|
|
|
let res = x ^ y; |
|
|
|
|
frame.status.update(res); |
|
|
|
|
frame.write(*dst, res)?; |
|
|
|
|
} |
|
|
|
|
Op::Xor(dst, src) => { |
|
|
|
|
Op::Cpl { dst, a } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut val = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*src)?; |
|
|
|
|
val ^= b; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
let x = frame.read(*a)?; |
|
|
|
|
let res = !x; |
|
|
|
|
frame.status.update(res); |
|
|
|
|
frame.write(*dst, res)?; |
|
|
|
|
} |
|
|
|
|
Op::Cpl(dst) => { |
|
|
|
|
Op::Rol { dst, a, n } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut val = frame.read(dst.as_rd())?; |
|
|
|
|
val = !val; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
let x = frame.read(*a)?; |
|
|
|
|
let y = frame.read(*n)?; |
|
|
|
|
if y > u32::MAX as u64 { |
|
|
|
|
frame.status.invalid = true; |
|
|
|
|
} else { |
|
|
|
|
let res = x.rotate_left(y as u32); |
|
|
|
|
frame.status.update(res); |
|
|
|
|
frame.write(*dst, res)?; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Op::Rol(dst, num) => { |
|
|
|
|
Op::Ror { dst, a, n } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut val = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*num)?; |
|
|
|
|
val = val.rotate_left(b as u32); // FIXME check overflow
|
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
let x = frame.read(*a)?; |
|
|
|
|
let y = frame.read(*n)?; |
|
|
|
|
if y > u32::MAX as u64 { |
|
|
|
|
frame.status.invalid = true; |
|
|
|
|
} else { |
|
|
|
|
let res = x.rotate_right(y as u32); |
|
|
|
|
frame.status.update(res); |
|
|
|
|
frame.write(*dst, res)?; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Op::Ror(dst, num) => { |
|
|
|
|
Op::Lsl { dst, a, n } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut val = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*num)?; |
|
|
|
|
val = val.rotate_right(b as u32); // FIXME check overflow
|
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
let x = frame.read(*a)?; |
|
|
|
|
let y = frame.read(*n)?; |
|
|
|
|
let res = x << y; |
|
|
|
|
frame.status.update(res); |
|
|
|
|
frame.write(*dst, res)?; |
|
|
|
|
} |
|
|
|
|
Op::Lsl(dst, num) => { |
|
|
|
|
Op::Lsr { dst, a, n } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut val = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*num)?; |
|
|
|
|
val = val << b; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
let x = frame.read(*a)?; |
|
|
|
|
let y = frame.read(*n)?; |
|
|
|
|
let res = x >> y; |
|
|
|
|
frame.status.update(res); |
|
|
|
|
frame.write(*dst, res)?; |
|
|
|
|
} |
|
|
|
|
Op::Lsr(dst, num) => { |
|
|
|
|
Op::Asr { dst, a, n } => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut val = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*num)?; |
|
|
|
|
val = val >> b; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
let x = frame.read(*a)?; |
|
|
|
|
let y = frame.read(*n)?; |
|
|
|
|
if y > u32::MAX as u64 { |
|
|
|
|
frame.status.invalid = true; |
|
|
|
|
} else { |
|
|
|
|
let res = x.signed_shr(y as u32); |
|
|
|
|
frame.status.update(res); |
|
|
|
|
frame.write(*dst, res)?; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Op::Asr(dst, num) => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut val = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*num)?; |
|
|
|
|
val = val.signed_shr(b as u32); // FIXME check overflow
|
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
Op::StoreStatus { dst } => { |
|
|
|
|
let packed = frame.status.store(); |
|
|
|
|
frame.write(*dst, packed)?; |
|
|
|
|
} |
|
|
|
|
Op::LoadStatus { src } => { |
|
|
|
|
let x = frame.read(*src)?; |
|
|
|
|
frame.status.load(x); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|