|
|
|
@ -3,6 +3,8 @@ use asm::instr::{Op, Cond}; |
|
|
|
|
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 num_traits::PrimInt; |
|
|
|
|
|
|
|
|
|
pub type CyclesSpent = usize; |
|
|
|
|
|
|
|
|
@ -12,6 +14,7 @@ pub struct EvalRes { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl RunThread { |
|
|
|
|
// TODO unit tests
|
|
|
|
|
pub fn eval_op(&mut self) -> Result<EvalRes, Fault> { |
|
|
|
|
let mut cycles = 1; |
|
|
|
|
let mut advance = 1; |
|
|
|
@ -19,6 +22,8 @@ impl RunThread { |
|
|
|
|
let mut frame = &mut self.frame; |
|
|
|
|
|
|
|
|
|
let op = self.program.read(frame.pc); |
|
|
|
|
|
|
|
|
|
debug!("------------------------"); |
|
|
|
|
debug!("{} | {:?}", frame.pc, op); |
|
|
|
|
|
|
|
|
|
/* Operations can be given different execution times when run in slow mode. */ |
|
|
|
@ -144,72 +149,196 @@ impl RunThread { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut a = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*src)?; |
|
|
|
|
|
|
|
|
|
let val = a.wrapping_add(b); |
|
|
|
|
let (val, ov) = if let Some(v) = a.checked_add(b) { |
|
|
|
|
(v, false) |
|
|
|
|
} else { |
|
|
|
|
(a.wrapping_add(b), true) |
|
|
|
|
}; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.status.overflow = b > Value::MAX - a; // TODO check
|
|
|
|
|
// TODO carry?
|
|
|
|
|
frame.status.overflow = ov; |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
} |
|
|
|
|
Op::Sub(dst, src) => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut a = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*src)?; |
|
|
|
|
|
|
|
|
|
let val = a.wrapping_sub(b); |
|
|
|
|
let (val, ov) = if let Some(v) = a.checked_sub(b) { |
|
|
|
|
(v, false) |
|
|
|
|
} else { |
|
|
|
|
(a.wrapping_sub(b), true) |
|
|
|
|
}; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
frame.status.overflow = b > a; |
|
|
|
|
// TODO carry?
|
|
|
|
|
frame.status.overflow = ov; |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
} |
|
|
|
|
Op::Mul(dst, src) => { |
|
|
|
|
frame.status.clear(); |
|
|
|
|
let mut a = frame.read(dst.as_rd())?; |
|
|
|
|
let mut b = frame.read(*src)?; |
|
|
|
|
|
|
|
|
|
let val = a.wrapping_mul(b); |
|
|
|
|
let (val, ov) = if let Some(v) = a.checked_mul(b) { |
|
|
|
|
(v, false) |
|
|
|
|
} else { |
|
|
|
|
(a.wrapping_mul(b), true) |
|
|
|
|
}; |
|
|
|
|
frame.status.zero = (val == 0); |
|
|
|
|
frame.status.positive = is_positive(val); |
|
|
|
|
frame.status.negative = is_negative(val); |
|
|
|
|
//frame.status.overflow = b > a; // TODO detect overflow
|
|
|
|
|
frame.status.overflow = ov; |
|
|
|
|
frame.write(*dst, val)?; |
|
|
|
|
} |
|
|
|
|
Op::Div(_, _) => { |
|
|
|
|
unimplemented!() |
|
|
|
|
Op::Div(dst, src) => { |
|
|
|
|
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, ov) = if let Some(v) = a.checked_div(b) { |
|
|
|
|
(v, false) |
|
|
|
|
} else { |
|
|
|
|
(a.wrapping_div(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)?; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Op::Mod(_, _, _) => { |
|
|
|
|
unimplemented!() |
|
|
|
|
Op::Mod(dst, src) => { |
|
|
|
|
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, ov) = if let Some(v) = a.checked_rem(b) { |
|
|
|
|
(v, false) |
|
|
|
|
} else { |
|
|
|
|
(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)?; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Op::And(_, _) => { |
|
|
|
|
unimplemented!() |
|
|
|
|
Op::DivRem(dst, remptr, src) => { |
|
|
|
|
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)?; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Op::Or(_, _) => { |
|
|
|
|
unimplemented!() |
|
|
|
|
Op::And(dst, src) => { |
|
|
|
|
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)?; |
|
|
|
|
} |
|
|
|
|
Op::Xor(_, _) => { |
|
|
|
|
unimplemented!() |
|
|
|
|
Op::Or(dst, src) => { |
|
|
|
|
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)?; |
|
|
|
|
} |
|
|
|
|
Op::Cpl(_) => { |
|
|
|
|
unimplemented!() |
|
|
|
|
Op::Xor(dst, src) => { |
|
|
|
|
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)?; |
|
|
|
|
} |
|
|
|
|
Op::Cpl(dst) => { |
|
|
|
|
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)?; |
|
|
|
|
} |
|
|
|
|
Op::Rol(_, _) => { |
|
|
|
|
unimplemented!() |
|
|
|
|
Op::Rol(dst, num) => { |
|
|
|
|
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)?; |
|
|
|
|
} |
|
|
|
|
Op::Ror(_, _) => { |
|
|
|
|
unimplemented!() |
|
|
|
|
Op::Ror(dst, num) => { |
|
|
|
|
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)?; |
|
|
|
|
} |
|
|
|
|
Op::Lsl(_, _) => { |
|
|
|
|
unimplemented!() |
|
|
|
|
Op::Lsl(dst, num) => { |
|
|
|
|
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)?; |
|
|
|
|
} |
|
|
|
|
Op::Lsr(_, _) => { |
|
|
|
|
unimplemented!() |
|
|
|
|
Op::Lsr(dst, num) => { |
|
|
|
|
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)?; |
|
|
|
|
} |
|
|
|
|
Op::Asr(_, _) => { |
|
|
|
|
unimplemented!() |
|
|
|
|
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)?; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|