basic float arith, wip float trig, abs
This commit is contained in:
+40
-14
@@ -27,8 +27,10 @@ pub enum ArithOp {
|
||||
SignExtend { dst: Wr, src: Rd, mask: BitMask },
|
||||
|
||||
Add { dst: Wr, a: Rd, b: Rd },
|
||||
Abs { dst: Wr, a: Rd },
|
||||
Sub { dst: Wr, a: Rd, b: Rd },
|
||||
Mul { dst: Wr, a: Rd, b: Rd },
|
||||
Pow { dst: Wr, a: Rd, pow: Rd },
|
||||
Div { dst: Wr, rem: Wr, a: Rd, div: Rd },
|
||||
// "Mod" is functionally equivalent to "Div" with the result discarded,
|
||||
// but status flags are updated by the remainder
|
||||
@@ -46,18 +48,42 @@ pub enum ArithOp {
|
||||
Lsr { dst: Wr, a: Rd, n: Rd },
|
||||
Asr { dst: Wr, a: Rd, n: Rd },
|
||||
|
||||
// IntToFloat { dst: Wr, a: Rd },
|
||||
// FloatToInt { dst: Wr, a: Rd },
|
||||
// FloatTest { a: Rd },
|
||||
// FloatCompare { a: Rd, b: Rd },
|
||||
// FloatRangeTest { val: Rd, a: Rd, b: Rd },
|
||||
// FloatRng { dst: Wr, min: Rd, max: Rd },
|
||||
// FloatRound { dst: Wr, a: Rd, b: Rd },
|
||||
// FloatCeil { dst: Wr, a: Rd, b: Rd },
|
||||
// FloatFloor { dst: Wr, a: Rd, b: Rd },
|
||||
// FloatAdd { dst: Wr, a: Rd, b: Rd },
|
||||
// FloatSub { dst: Wr, a: Rd, b: Rd },
|
||||
// FloatMul { dst: Wr, a: Rd, b: Rd },
|
||||
// FloatDiv { dst: Wr, rem: Wr, a: Rd, div: Rd },
|
||||
// FloatMod { dst: Wr, a: Rd, div: Rd },
|
||||
IntToFloat { dst: Wr, a: Rd },
|
||||
FloatToInt { dst: Wr, a: Rd, mode: FloatToIntMode },
|
||||
FloatTest { a: Rd },
|
||||
FloatCompare { a: Rd, b: Rd },
|
||||
FloatRangeTest { val: Rd, a: Rd, b: Rd },
|
||||
FloatRng { dst: Wr, min: Rd, max: Rd },
|
||||
FloatAdd { dst: Wr, a: Rd, b: Rd },
|
||||
FloatSub { dst: Wr, a: Rd, b: Rd },
|
||||
FloatMul { dst: Wr, a: Rd, b: Rd },
|
||||
FloatPow { dst: Wr, a: Rd, pow: Rd },
|
||||
FloatRoot { dst: Wr, a: Rd, root: Rd },
|
||||
FloatHyp { dst: Wr, a: Rd, b: Rd },
|
||||
FloatDiv { dst: Wr, rem: Wr, a: Rd, div: Rd },
|
||||
FloatMod { dst: Wr, a: Rd, div: Rd },
|
||||
FloatAbs { dst: Wr, a: Rd },
|
||||
|
||||
FloatSin { dst: Wr, f: Rd },
|
||||
FloatAsin { dst: Wr, a: Rd },
|
||||
FloatCos { dst: Wr, f: Rd },
|
||||
FloatAcos { dst: Wr, a: Rd },
|
||||
FloatTan { dst: Wr, f: Rd },
|
||||
FloatAtan { dst: Wr, a: Rd },
|
||||
FloatAtan2 { dst: Wr, y: Rd, x: Rd },
|
||||
FloatCot { dst: Wr, f: Rd },
|
||||
FloatAcot { dst: Wr, a: Rd },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub enum FloatToIntMode {
|
||||
Floor,
|
||||
Ceil,
|
||||
Round,
|
||||
}
|
||||
|
||||
impl Default for FloatToIntMode {
|
||||
fn default() -> Self {
|
||||
Self::Round
|
||||
}
|
||||
}
|
||||
|
||||
+180
-5
@@ -10,14 +10,35 @@ use crsn::sexp;
|
||||
use crsn::sexp::Sexp;
|
||||
use crsn::utils::A;
|
||||
|
||||
use crate::defs::ArithOp;
|
||||
use crate::defs::{ArithOp, FloatToIntMode};
|
||||
use crsn::asm::instr::cond::Flag;
|
||||
use rand::Rng;
|
||||
|
||||
#[inline]
|
||||
fn f2u(f: f64) -> u64 {
|
||||
unsafe { std::mem::transmute(f) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn u2f(f: u64) -> f64 {
|
||||
unsafe { std::mem::transmute(f) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn i2u(f: i64) -> u64 {
|
||||
unsafe { std::mem::transmute(f) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn u2i(f: u64) -> i64 {
|
||||
unsafe { std::mem::transmute(f) }
|
||||
}
|
||||
|
||||
impl OpTrait for ArithOp {
|
||||
fn execute(&self, _ti: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
|
||||
let eres = EvalRes::default();
|
||||
match self {
|
||||
// Integers
|
||||
ArithOp::Test { a } => {
|
||||
state.clear_status();
|
||||
let res = state.read(a)?;
|
||||
@@ -142,6 +163,122 @@ impl OpTrait for ArithOp {
|
||||
state.write(dst, remainder)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Floating point
|
||||
|
||||
ArithOp::FloatToInt { dst, a, mode } => {
|
||||
state.clear_status();
|
||||
let val : f64 = u2f(state.read(a)?);
|
||||
let res = i2u(match mode {
|
||||
FloatToIntMode::Floor => val.floor(),
|
||||
FloatToIntMode::Ceil => val.ceil(),
|
||||
FloatToIntMode::Round => val.round(),
|
||||
} as i64);
|
||||
state.update_status(res);
|
||||
state.write(dst, res)?;
|
||||
}
|
||||
ArithOp::IntToFloat { dst, a } => {
|
||||
state.clear_status();
|
||||
let val : f64 = u2i(state.read(a)?) as f64;
|
||||
state.update_status_float(val);
|
||||
state.write(dst, f2u(val))?;
|
||||
}
|
||||
ArithOp::FloatTest { a } => {
|
||||
state.clear_status();
|
||||
let res = u2f(state.read(a)?);
|
||||
state.update_status_float(res);
|
||||
}
|
||||
ArithOp::FloatCompare { a, b } => {
|
||||
state.clear_status();
|
||||
let x = u2f(state.read(a)?);
|
||||
let y = u2f(state.read(b)?);
|
||||
state.set_flag(Flag::Equal, x == y);
|
||||
state.set_flag(Flag::Lower, x < y);
|
||||
state.set_flag(Flag::Greater, x > y);
|
||||
// Test flags are set when both arguments have the property
|
||||
if x == y {
|
||||
state.update_status_float(x);
|
||||
}
|
||||
}
|
||||
ArithOp::FloatRangeTest { val, a, b } => {
|
||||
state.clear_status();
|
||||
let val = u2f(state.read(val)?);
|
||||
let a = u2f(state.read(a)?);
|
||||
let b = u2f(state.read(b)?);
|
||||
state.set_flag(Flag::Equal, val >= a && val <= b);
|
||||
state.set_flag(Flag::Lower, val < a);
|
||||
state.set_flag(Flag::Greater, val > b);
|
||||
state.update_status_float(val);
|
||||
}
|
||||
ArithOp::FloatRng { dst, min, max } => {
|
||||
state.clear_status();
|
||||
let min = u2f(state.read(min)?);
|
||||
let max = u2f(state.read(max)?);
|
||||
|
||||
let val = if min == max {
|
||||
min
|
||||
} else if min > max {
|
||||
state.set_flag(Flag::Invalid, true);
|
||||
min
|
||||
} else {
|
||||
rand::thread_rng()
|
||||
.gen_range(min, max)
|
||||
};
|
||||
state.write(dst, f2u(val))?;
|
||||
state.update_status_float(val);
|
||||
}
|
||||
ArithOp::FloatAdd { dst, a, b } => {
|
||||
state.clear_status();
|
||||
let x = u2f(state.read(a)?);
|
||||
let y = u2f(state.read(b)?);
|
||||
let res = x + y;
|
||||
state.update_status_float(res);
|
||||
state.write(dst, f2u(res))?;
|
||||
}
|
||||
ArithOp::FloatSub { dst, a, b } => {
|
||||
state.clear_status();
|
||||
let x = u2f(state.read(a)?);
|
||||
let y = u2f(state.read(b)?);
|
||||
let res = x - y;
|
||||
state.update_status_float(res);
|
||||
state.write(dst, f2u(res))?;
|
||||
}
|
||||
ArithOp::FloatMul { dst, a, b } => {
|
||||
state.clear_status();
|
||||
let x = u2f(state.read(a)?);
|
||||
let y = u2f(state.read(b)?);
|
||||
let res = x * y;
|
||||
state.update_status_float(res);
|
||||
state.write(dst, f2u(res))?;
|
||||
}
|
||||
ArithOp::FloatDiv { dst, rem, a, div } => {
|
||||
state.clear_status();
|
||||
let x = u2f(state.read(a)?);
|
||||
let d = u2f(state.read(div)?);
|
||||
if d == 0.0 {
|
||||
state.set_flag(Flag::Invalid, true);
|
||||
} else {
|
||||
let res = x / d;
|
||||
let remainder = x % d;
|
||||
state.update_status_float(res);
|
||||
state.write(dst, f2u(res))?;
|
||||
state.write(rem, f2u(remainder))?;
|
||||
}
|
||||
}
|
||||
ArithOp::FloatMod { dst, a, div } => {
|
||||
state.clear_status();
|
||||
let x = u2f(state.read(a)?);
|
||||
let d = u2f(state.read(div)?);
|
||||
if d == 0.0 {
|
||||
state.set_flag(Flag::Invalid, true);
|
||||
} else {
|
||||
let rem = x % d;
|
||||
state.update_status_float(rem);
|
||||
state.write(dst, f2u(rem))?;
|
||||
}
|
||||
}
|
||||
|
||||
// Bitwise
|
||||
ArithOp::And { dst, a, b } => {
|
||||
state.clear_status();
|
||||
let x = state.read(a)?;
|
||||
@@ -282,6 +419,8 @@ impl OpTrait for ArithOp {
|
||||
state.update_status(res);
|
||||
state.write(dst, res)?;
|
||||
}
|
||||
|
||||
_ => unimplemented!() // TODO implement float trig etc
|
||||
}
|
||||
|
||||
Ok(eres)
|
||||
@@ -289,19 +428,19 @@ impl OpTrait for ArithOp {
|
||||
|
||||
fn to_sexp(&self) -> Sexp {
|
||||
match self {
|
||||
ArithOp::Add { dst, a, b } => to_sexp_2_or_3("add", dst, a, b),
|
||||
ArithOp::Test { a } => sexp::list(&[A("test"), A(a)]),
|
||||
ArithOp::Test { a } => sexp::list(&[A("tst"), A(a)]),
|
||||
ArithOp::Compare { a, b } => sexp::list(&[A("cmp"), A(a), A(b)]),
|
||||
ArithOp::RangeTest { val, a: start, b: end } => sexp::list(&[A("rcmp"), A(val), A(start), A(end)]),
|
||||
ArithOp::Rng { dst, min, max } => {
|
||||
if min.is_immediate_equal(0) && max.is_immediate_equal(u64::MAX) {
|
||||
if min.is_imm_equal(0) && max.is_imm_equal(u64::MAX) {
|
||||
sexp::list(&[A("rng"), A(dst)])
|
||||
} else if min.is_immediate_equal(0) {
|
||||
} else if min.is_imm_equal(0) {
|
||||
sexp::list(&[A("rng"), A(dst), A(max)])
|
||||
} else {
|
||||
sexp::list(&[A("rng"), A(dst), A(min), A(max)])
|
||||
}
|
||||
}
|
||||
ArithOp::Add { dst, a, b } => to_sexp_2_or_3("add", dst, a, b),
|
||||
ArithOp::Sub { dst, a, b } => to_sexp_2_or_3("sub", dst, a, b),
|
||||
ArithOp::Mul { dst, a, b } => to_sexp_2_or_3("mul", dst, a, b),
|
||||
ArithOp::Div { dst, rem, a, div } => {
|
||||
@@ -316,6 +455,40 @@ impl OpTrait for ArithOp {
|
||||
}
|
||||
}
|
||||
ArithOp::Mod { dst, a, div } => to_sexp_2_or_3("mod", dst, a, div),
|
||||
|
||||
// TODO render as float
|
||||
ArithOp::FloatTest { a } => sexp::list(&[A("tstf"), A(a)]),
|
||||
ArithOp::FloatCompare { a, b } => sexp::list(&[A("cmpf"), A(a), A(b)]),
|
||||
ArithOp::FloatRangeTest { val, a: start, b: end } => sexp::list(&[A("rcmpf"), A(val), A(start), A(end)]),
|
||||
ArithOp::FloatRng { dst, min, max } => {
|
||||
if min.is_imm_equal(0f64.to_bits()) && max.is_imm_equal(f64::MAX.to_bits()) {
|
||||
sexp::list(&[A("rngf"), A(dst)])
|
||||
} else if min.is_imm_equal(0) {
|
||||
sexp::list(&[A("rngf"), A(dst), A(max)])
|
||||
} else {
|
||||
sexp::list(&[A("rngf"), A(dst), A(min), A(max)])
|
||||
}
|
||||
}
|
||||
ArithOp::FloatAdd { dst, a, b } => to_sexp_2_or_3("addf", dst, a, b),
|
||||
ArithOp::FloatSub { dst, a, b } => to_sexp_2_or_3("subf", dst, a, b),
|
||||
ArithOp::FloatMul { dst, a, b } => to_sexp_2_or_3("mulf", dst, a, b),
|
||||
ArithOp::FloatDiv { dst, rem, a, div } => {
|
||||
if rem.is_discard() {
|
||||
to_sexp_2_or_3("divf", dst, a, div)
|
||||
} else {
|
||||
if &dst.as_rd() == a {
|
||||
sexp::list(&[A("divrf"), A(dst), A(rem), A(div)])
|
||||
} else {
|
||||
sexp::list(&[A("divrf"), A(dst), A(rem), A(a), A(div)])
|
||||
}
|
||||
}
|
||||
}
|
||||
ArithOp::FloatMod { dst, a, div } => to_sexp_2_or_3("modf", dst, a, div),
|
||||
ArithOp::IntToFloat { dst, a } => to_sexp_1_or_2("itf", dst, a),
|
||||
ArithOp::FloatToInt { dst, a, mode: FloatToIntMode::Floor } => to_sexp_1_or_2("ftif", dst, a),
|
||||
ArithOp::FloatToInt { dst, a, mode: FloatToIntMode::Round } => to_sexp_1_or_2("ftir", dst, a),
|
||||
ArithOp::FloatToInt { dst, a, mode: FloatToIntMode::Ceil } => to_sexp_1_or_2("ftic", dst, a),
|
||||
|
||||
ArithOp::And { dst, a, b } => to_sexp_2_or_3("and", dst, a, b),
|
||||
ArithOp::Or { dst, a, b } => to_sexp_2_or_3("or", dst, a, b),
|
||||
ArithOp::Xor { dst, a, b } => to_sexp_2_or_3("xor", dst, a, b),
|
||||
@@ -333,6 +506,8 @@ impl OpTrait for ArithOp {
|
||||
ArithOp::Clz { dst, src, mask: slice } => to_sexp_1_or_2(&format!("clz{}", slice), dst, src),
|
||||
ArithOp::Clo { dst, src, mask: slice } => to_sexp_1_or_2(&format!("clo{}", slice), dst, src),
|
||||
ArithOp::SignExtend { dst, src, mask: slice } => to_sexp_1_or_2(&format!("se{}", slice), dst, src),
|
||||
|
||||
_ => unimplemented!() // FIXME
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+261
-8
@@ -4,9 +4,7 @@ use crsn::asm::instr::op::OpKind;
|
||||
use crsn::asm::parse::arg_parser::TokenParser;
|
||||
use crsn::module::ParseRes;
|
||||
use crsn::sexp::SourcePosition;
|
||||
|
||||
use crate::defs::ArithOp;
|
||||
|
||||
use crate::defs::{ArithOp, FloatToIntMode};
|
||||
|
||||
pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
||||
Ok(ParseRes::ext(match keyword {
|
||||
@@ -33,14 +31,14 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP
|
||||
1 => {
|
||||
ArithOp::Rng {
|
||||
dst: args.next_wr()?,
|
||||
min: Rd::immediate(0),
|
||||
max: Rd::immediate(u64::MAX),
|
||||
min: Rd::new_imm(0),
|
||||
max: Rd::new_imm(u64::MAX),
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
ArithOp::Rng {
|
||||
dst: args.next_wr()?,
|
||||
min: Rd::immediate(0),
|
||||
min: Rd::new_imm(0),
|
||||
max: args.next_rd()?,
|
||||
}
|
||||
}
|
||||
@@ -61,12 +59,12 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP
|
||||
|
||||
"inc" => {
|
||||
let (dst, a) = args.parse_wr_rd()?;
|
||||
ArithOp::Add { dst, a, b: Rd::immediate(1) }
|
||||
ArithOp::Add { dst, a, b: Rd::new_imm(1) }
|
||||
}
|
||||
|
||||
"dec" => {
|
||||
let (dst, a) = args.parse_wr_rd()?;
|
||||
ArithOp::Sub { dst, a, b: Rd::immediate(1) }
|
||||
ArithOp::Sub { dst, a, b: Rd::new_imm(1) }
|
||||
}
|
||||
|
||||
"add" => {
|
||||
@@ -74,6 +72,11 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP
|
||||
ArithOp::Add { dst, a, b }
|
||||
}
|
||||
|
||||
"abs" => {
|
||||
let (dst, a) = args.parse_wr_rd()?;
|
||||
ArithOp::Abs { dst, a }
|
||||
}
|
||||
|
||||
"sub" => {
|
||||
let (dst, a, b) = args.parse_wr_rd_rd()?;
|
||||
ArithOp::Sub { dst, a, b }
|
||||
@@ -84,6 +87,11 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP
|
||||
ArithOp::Mul { dst, a, b }
|
||||
}
|
||||
|
||||
"pow" => {
|
||||
let (dst, a, pow) = args.parse_wr_rd_rd()?;
|
||||
ArithOp::Pow { dst, a, pow }
|
||||
}
|
||||
|
||||
"divr" => {
|
||||
match args.len() {
|
||||
3 => {
|
||||
@@ -191,6 +199,251 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP
|
||||
ArithOp::Rbit { dst, src }
|
||||
}
|
||||
|
||||
"cmpf" => {
|
||||
let parsed = ArithOp::FloatCompare {
|
||||
a: args.next_rd()?.imm_to_float(),
|
||||
b: args.next_rd()?.imm_to_float(),
|
||||
};
|
||||
args.ensure_empty("two input arguments")?;
|
||||
parsed
|
||||
}
|
||||
|
||||
"frcmp" => {
|
||||
let parsed = ArithOp::FloatRangeTest {
|
||||
val: args.next_rd()?.imm_to_float(),
|
||||
a: args.next_rd()?.imm_to_float(),
|
||||
b: args.next_rd()?.imm_to_float(),
|
||||
};
|
||||
args.ensure_empty("3 arguments (value, min, max)")?;
|
||||
parsed
|
||||
}
|
||||
|
||||
"ftst" => {
|
||||
let arg = args.next_rd()?;
|
||||
args.ensure_empty("1 input argument")?;
|
||||
ArithOp::FloatTest { a: arg.imm_to_float() }
|
||||
}
|
||||
|
||||
"frng" => {
|
||||
let parsed = match args.len() {
|
||||
1 => {
|
||||
ArithOp::FloatRng {
|
||||
dst: args.next_wr()?,
|
||||
min: Rd::new_float(0.0),
|
||||
max: Rd::new_float(f64::MAX),
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
ArithOp::FloatRng {
|
||||
dst: args.next_wr()?,
|
||||
min: Rd::new_float(0.0),
|
||||
max: args.next_rd()?.imm_to_float(),
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
ArithOp::FloatRng {
|
||||
dst: args.next_wr()?,
|
||||
min: args.next_rd()?.imm_to_float(),
|
||||
max: args.next_rd()?.imm_to_float(),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(CrsnError::Parse("Rng requires 1, 2 or 3 arguments".into(), op_pos.clone()));
|
||||
}
|
||||
};
|
||||
args.ensure_empty("1 (dst) or 3 (dst, min, max) arguments")?;
|
||||
parsed
|
||||
}
|
||||
|
||||
"fadd" => {
|
||||
let (dst, a, b) = args.parse_wr_rd_rd()?;
|
||||
ArithOp::FloatAdd {
|
||||
dst,
|
||||
a: a.imm_to_float(),
|
||||
b: b.imm_to_float(),
|
||||
}
|
||||
}
|
||||
|
||||
"fsub" => {
|
||||
let (dst, a, b) = args.parse_wr_rd_rd()?;
|
||||
ArithOp::FloatSub {
|
||||
dst,
|
||||
a: a.imm_to_float(),
|
||||
b: b.imm_to_float(),
|
||||
}
|
||||
}
|
||||
|
||||
"fmul" => {
|
||||
let (dst, a, b) = args.parse_wr_rd_rd()?;
|
||||
ArithOp::FloatMul {
|
||||
dst,
|
||||
a: a.imm_to_float(),
|
||||
b: b.imm_to_float(),
|
||||
}
|
||||
}
|
||||
|
||||
"fpow" => {
|
||||
let (dst, a, pow) = args.parse_wr_rd_rd()?;
|
||||
ArithOp::FloatPow {
|
||||
dst,
|
||||
a: a.imm_to_float(),
|
||||
pow: pow.imm_to_float()
|
||||
}
|
||||
}
|
||||
|
||||
"froot" => {
|
||||
let (dst, a, root) = args.parse_wr_rd_rd()?;
|
||||
ArithOp::FloatRoot {
|
||||
dst,
|
||||
a: a.imm_to_float(),
|
||||
root: root.imm_to_float()
|
||||
}
|
||||
}
|
||||
|
||||
"fhyp" => {
|
||||
let (dst, a, b) = args.parse_wr_rd_rd()?;
|
||||
ArithOp::FloatHyp {
|
||||
dst,
|
||||
a: a.imm_to_float(),
|
||||
b: a.imm_to_float(),
|
||||
}
|
||||
}
|
||||
|
||||
"fdiv" => {
|
||||
let (dst, a, div) = args.parse_wr_rd_rd()?;
|
||||
ArithOp::FloatDiv {
|
||||
dst,
|
||||
rem: Wr::discard(),
|
||||
a: a.imm_to_float(),
|
||||
div: div.imm_to_float(),
|
||||
}
|
||||
}
|
||||
|
||||
"fdivr" => {
|
||||
match args.len() {
|
||||
3 => {
|
||||
let dst = args.next_rdwr()?;
|
||||
let rem = args.next_wr()?;
|
||||
let div = args.next_rd()?;
|
||||
ArithOp::FloatDiv {
|
||||
dst: dst.wr(),
|
||||
rem,
|
||||
a: dst.rd().imm_to_float(),
|
||||
div: div.imm_to_float(),
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
ArithOp::FloatDiv {
|
||||
dst: args.next_wr()?,
|
||||
rem: args.next_wr()?,
|
||||
a: args.next_rd()?.imm_to_float(),
|
||||
div: args.next_rd()?.imm_to_float(),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(CrsnError::Parse("DivRF requires 3 or 4 arguments".into(), op_pos.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"fmod" => {
|
||||
let (dst, a, div) = args.parse_wr_rd_rd()?;
|
||||
ArithOp::FloatMod {
|
||||
dst,
|
||||
a: a.imm_to_float(),
|
||||
div: div.imm_to_float(),
|
||||
}
|
||||
}
|
||||
|
||||
"itf" => {
|
||||
let (dst, a) = args.parse_wr_rd()?;
|
||||
ArithOp::IntToFloat {
|
||||
dst,
|
||||
a: a.imm_to_float()
|
||||
}
|
||||
}
|
||||
|
||||
"fti" | "ftir" => {
|
||||
let (dst, a) = args.parse_wr_rd()?;
|
||||
ArithOp::FloatToInt {
|
||||
dst,
|
||||
a: a.imm_to_float(),
|
||||
mode: FloatToIntMode::Round
|
||||
}
|
||||
}
|
||||
|
||||
"ftic" => {
|
||||
let (dst, a) = args.parse_wr_rd()?;
|
||||
ArithOp::FloatToInt {
|
||||
dst,
|
||||
a: a.imm_to_float(),
|
||||
mode: FloatToIntMode::Ceil
|
||||
}
|
||||
}
|
||||
|
||||
"ftif" => {
|
||||
let (dst, a) = args.parse_wr_rd()?;
|
||||
ArithOp::FloatToInt {
|
||||
dst,
|
||||
a: a.imm_to_float(),
|
||||
mode: FloatToIntMode::Floor
|
||||
}
|
||||
}
|
||||
|
||||
"fabs" => {
|
||||
let (dst, a) = args.parse_wr_rd()?;
|
||||
ArithOp::FloatAbs { dst, a: f.imm_to_float() }
|
||||
}
|
||||
|
||||
"fsin" => {
|
||||
let (dst, f) = args.parse_wr_rd()?;
|
||||
ArithOp::FloatSin { dst, f: f.imm_to_float() }
|
||||
}
|
||||
|
||||
"fasin" => {
|
||||
let (dst, a) = args.parse_wr_rd()?;
|
||||
ArithOp::FloatAsin { dst, a: a.imm_to_float() }
|
||||
}
|
||||
|
||||
"fcos" => {
|
||||
let (dst, f) = args.parse_wr_rd()?;
|
||||
ArithOp::FloatCos { dst, f: f.imm_to_float() }
|
||||
}
|
||||
|
||||
"facos" => {
|
||||
let (dst, a) = args.parse_wr_rd()?;
|
||||
ArithOp::FloatAcos { dst, a: a.imm_to_float() }
|
||||
}
|
||||
|
||||
"ftan" => {
|
||||
let (dst, f) = args.parse_wr_rd()?;
|
||||
ArithOp::FloatTan { dst, f: f.imm_to_float() }
|
||||
}
|
||||
|
||||
"fatan" => {
|
||||
let (dst, a) = args.parse_wr_rd()?;
|
||||
ArithOp::FloatAtan { dst, a: a.imm_to_float() }
|
||||
}
|
||||
|
||||
"fatan2" => {
|
||||
let (dst, a, b) = args.parse_wr_rd_rd()?;
|
||||
ArithOp::FloatAtan2 {
|
||||
dst,
|
||||
y: a.imm_to_float(),
|
||||
x: b.imm_to_float(),
|
||||
}
|
||||
}
|
||||
|
||||
"fcot" => {
|
||||
let (dst, f) = args.parse_wr_rd()?;
|
||||
ArithOp::FloatCot { dst, f: f.imm_to_float() }
|
||||
}
|
||||
|
||||
"facot" => {
|
||||
let (dst, a) = args.parse_wr_rd()?;
|
||||
ArithOp::FloatAcot { dst, a: a.imm_to_float() }
|
||||
}
|
||||
|
||||
other => {
|
||||
if let Some((dst, src, mask)) = args.parse_masked_wr_rd(other, "clz")? {
|
||||
if !dst.disp_equals(src) && mask.dst_pos != 0 {
|
||||
|
||||
Reference in New Issue
Block a user