From 9723ac72be630aaef931931e4e7bc2a261c41ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Tue, 20 Oct 2020 00:26:08 +0200 Subject: [PATCH] fixes, more trig, demo with floats --- Cargo.lock | 1 + crsn/src/asm/data/rd.rs | 19 +- crsn/src/runtime/frame/status.rs | 9 +- crsn_arith/Cargo.toml | 1 + crsn_arith/src/defs.rs | 19 +- crsn_arith/src/exec.rs | 295 ++++++++++++++++++++++++++++--- crsn_arith/src/lib.rs | 20 +++ crsn_arith/src/parse.rs | 73 ++++++-- examples/screen_trig.csn | 34 ++++ 9 files changed, 421 insertions(+), 50 deletions(-) create mode 100644 examples/screen_trig.csn diff --git a/Cargo.lock b/Cargo.lock index ba8c491..f03afcb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -188,6 +188,7 @@ name = "crsn_arith" version = "0.1.0" dependencies = [ "crsn", + "log", "num-traits", "rand 0.7.3", ] diff --git a/crsn/src/asm/data/rd.rs b/crsn/src/asm/data/rd.rs index edbc875..5410d61 100644 --- a/crsn/src/asm/data/rd.rs +++ b/crsn/src/asm/data/rd.rs @@ -24,15 +24,18 @@ impl Rd { Rd(RdData::Immediate(val.to_bits())) } - /// Convert immediate read to float + /// Convert immediate integer to float pub fn imm_to_float(self) -> Rd { - match self { - Rd(RdData::Immediate(v)) => { - let signed : i64 = unsafe { std::mem::transmute(v) }; - Rd::new_float(signed as f64) - } - other => other - } + self + + // FIXME + // match self { + // Rd(RdData::Immediate(v)) => { + // let signed : i64 = unsafe { std::mem::transmute(v) }; + // Rd::new_float(signed as f64) + // } + // other => other + // } } pub fn is_imm_equal(self, other: Value) -> bool { diff --git a/crsn/src/runtime/frame/status.rs b/crsn/src/runtime/frame/status.rs index 0137169..dec3d5a 100644 --- a/crsn/src/runtime/frame/status.rs +++ b/crsn/src/runtime/frame/status.rs @@ -4,6 +4,7 @@ use std::fmt; use crate::asm::data::literal::{is_negative, is_positive, Value}; use crate::asm::instr::Cond; use crate::asm::instr::cond::Flag; +use num_traits::Zero; #[derive(Default, Clone, Debug)] pub struct StatusFlags { @@ -80,9 +81,11 @@ impl StatusFlags { #[inline(always)] pub fn update_float(&mut self, val: f64) { - self.zero = val == 0.0; - self.positive = val > 0.0; - self.negative = val < 0.0; + self.invalid = val.is_nan(); + self.overflow = val.is_infinite(); + self.zero = val.is_zero(); + self.positive = val.is_sign_positive(); + self.negative = val.is_sign_negative(); } #[inline(always)] diff --git a/crsn_arith/Cargo.toml b/crsn_arith/Cargo.toml index 7504dfa..2b0874c 100644 --- a/crsn_arith/Cargo.toml +++ b/crsn_arith/Cargo.toml @@ -10,3 +10,4 @@ edition = "2018" crsn = { path = "../crsn" } num-traits = "0.2.12" rand = "0.7.3" +log = "0.4.11" diff --git a/crsn_arith/src/defs.rs b/crsn_arith/src/defs.rs index 7bfba33..04c620f 100644 --- a/crsn_arith/src/defs.rs +++ b/crsn_arith/src/defs.rs @@ -28,6 +28,7 @@ pub enum ArithOp { Add { dst: Wr, a: Rd, b: Rd }, Abs { dst: Wr, a: Rd }, + Sgn { 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 }, @@ -63,16 +64,26 @@ pub enum ArithOp { FloatDiv { dst: Wr, rem: Wr, a: Rd, div: Rd }, FloatMod { dst: Wr, a: Rd, div: Rd }, FloatAbs { dst: Wr, a: Rd }, + FloatSgn { dst: Wr, a: Rd }, - FloatSin { dst: Wr, f: Rd }, + FloatSin { dst: Wr, a: Rd }, FloatAsin { dst: Wr, a: Rd }, - FloatCos { dst: Wr, f: Rd }, + FloatCos { dst: Wr, a: Rd }, FloatAcos { dst: Wr, a: Rd }, - FloatTan { dst: Wr, f: Rd }, + FloatTan { dst: Wr, a: Rd }, FloatAtan { dst: Wr, a: Rd }, FloatAtan2 { dst: Wr, y: Rd, x: Rd }, - FloatCot { dst: Wr, f: Rd }, + FloatCot { dst: Wr, a: Rd }, FloatAcot { dst: Wr, a: Rd }, + + FloatHypSin { dst: Wr, a: Rd }, + FloatHypAsin { dst: Wr, a: Rd }, + FloatHypCos { dst: Wr, a: Rd }, + FloatHypAcos { dst: Wr, a: Rd }, + FloatHypTan { dst: Wr, a: Rd }, + FloatHypAtan { dst: Wr, a: Rd }, + FloatHypCot { dst: Wr, a: Rd }, + FloatHypAcot { dst: Wr, a: Rd }, } #[derive(Debug, Clone, Copy, Eq, PartialEq)] diff --git a/crsn_arith/src/exec.rs b/crsn_arith/src/exec.rs index cf4b1b8..1392656 100644 --- a/crsn_arith/src/exec.rs +++ b/crsn_arith/src/exec.rs @@ -1,6 +1,6 @@ use std::ops::Rem; -use num_traits::PrimInt; +use num_traits::{PrimInt}; use crsn::asm::data::{Rd, Wr}; use crsn::module::{EvalRes, OpTrait}; @@ -13,24 +13,25 @@ use crsn::utils::A; use crate::defs::{ArithOp, FloatToIntMode}; use crsn::asm::instr::cond::Flag; use rand::Rng; +use std::f64::consts::{PI, FRAC_PI_2}; #[inline] -fn f2u(f: f64) -> u64 { +pub(crate) fn f2u(f: f64) -> u64 { unsafe { std::mem::transmute(f) } } #[inline] -fn u2f(f: u64) -> f64 { +pub(crate) fn u2f(f: u64) -> f64 { unsafe { std::mem::transmute(f) } } #[inline] -fn i2u(f: i64) -> u64 { +pub(crate) fn i2u(f: i64) -> u64 { unsafe { std::mem::transmute(f) } } #[inline] -fn u2i(f: u64) -> i64 { +pub(crate) fn u2i(f: u64) -> i64 { unsafe { std::mem::transmute(f) } } @@ -174,14 +175,17 @@ impl OpTrait for ArithOp { FloatToIntMode::Ceil => val.ceil(), FloatToIntMode::Round => val.round(), } as i64); + trace!("fti {} -> {}", val, res); 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))?; + let i = u2i(state.read(a)?); + let res: f64 = i as f64; + trace!("itf {} -> {}", i, res); + state.update_status_float(res); + state.write(dst, f2u(res))?; } ArithOp::FloatTest { a } => { state.clear_status(); @@ -419,8 +423,227 @@ impl OpTrait for ArithOp { state.update_status(res); state.write(dst, res)?; } + ArithOp::Abs { dst, a } => { + state.clear_status(); + let x = u2i(state.read(a)?); + let res = i2u(x.abs()); + state.update_status(res); + state.write(dst, res)?; + } + ArithOp::Sgn { dst, a } => { + state.clear_status(); + let x = u2i(state.read(a)?); + let res = i2u(if x >= 0 { 0 } else { -1 }); + state.update_status(res); + state.write(dst, res)?; + } + ArithOp::Pow { dst, a, pow } => { + state.clear_status(); + let x = state.read(a)?; + let p = state.read(pow)?; + if p > u32::MAX as u64 { + state.set_flag(Flag::Invalid, true); + } else { + let res = x.pow(p as u32); + state.update_status(res); + state.write(dst, res)?; + } + } + ArithOp::FloatPow { dst, a, pow } => { + state.clear_status(); + let x = u2f(state.read(a)?); + let p = u2f(state.read(pow)?); + let res = x.powf(p); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + ArithOp::FloatRoot { dst, a, root } => { + state.clear_status(); + let x = u2f(state.read(a)?); + let p = u2f(state.read(root)?); + if p == 0f64 { + state.set_flag(Flag::Invalid, true); + } else { + let res = x.powf(1f64 / p); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + } + ArithOp::FloatHyp { dst, a, b } => { + state.clear_status(); + let a = u2f(state.read(a)?); + let b = u2f(state.read(b)?); + let res = a.hypot(b); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + ArithOp::FloatAbs { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + let res = a.abs(); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + ArithOp::FloatSgn { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + let res = a.signum(); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + /* Simple trig */ + ArithOp::FloatSin { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + let res = a.sin(); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + ArithOp::FloatAsin { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + let res = a.asin(); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + ArithOp::FloatCos { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + let res = a.cos(); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + ArithOp::FloatAcos { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + let res = a.acos(); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + ArithOp::FloatTan { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + let res = a.tan(); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + ArithOp::FloatAtan { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + let res = a.atan(); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + ArithOp::FloatAtan2 { dst, y, x } => { + state.clear_status(); + let a = u2f(state.read(y)?); + let b = u2f(state.read(x)?); + let res = a.atan2(b); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + ArithOp::FloatCot { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + let tan = a.tan(); + if tan == 0.0 { + state.set_flag(Flag::Invalid, true); + } else { + let res = 1f64 / tan; + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + } + ArithOp::FloatAcot { dst, a } => { + state.clear_status(); + let x = u2f(state.read(a)?); + + // TODO verify + let res = if x > 1.0 { + (1.0/x).atan() + } else if x < -1.0 { + PI + (1.0/x).atan() + } else { + FRAC_PI_2 - x.atan() + }; - _ => unimplemented!() // TODO implement float trig etc + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + /* Hyperbolic trig */ + ArithOp::FloatHypSin { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + let res = a.sinh(); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + ArithOp::FloatHypAsin { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + let res = a.asinh(); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + ArithOp::FloatHypCos { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + let res = a.cosh(); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + ArithOp::FloatHypAcos { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + if a > 1.0 { + let res = a.acos(); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + } + ArithOp::FloatHypTan { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + let res = a.tanh(); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + ArithOp::FloatHypAtan { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + if a > -1.0 && a < 1.0 { + let res = a.atanh(); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } else { + state.set_flag(Flag::Invalid, true); + } + } + ArithOp::FloatHypCot { dst, a } => { + state.clear_status(); + let a = u2f(state.read(a)?); + let tan = a.tanh(); + if tan == 0.0 { + state.set_flag(Flag::Invalid, true); + } else { + let res = 1f64 / tan; + state.update_status_float(res); + state.write(dst, f2u(res))?; + } + } + ArithOp::FloatHypAcot { dst, a } => { + state.clear_status(); + let x = u2f(state.read(a)?); + + // TODO verify + if x > 1.0 || x < -1.0 { + let res = (1.0/x).atanh(); + state.update_status_float(res); + state.write(dst, f2u(res))?; + } else { + state.set_flag(Flag::Invalid, true); + }; + } } Ok(eres) @@ -457,33 +680,33 @@ 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::FloatTest { a } => sexp::list(&[A("ftst"), A(a)]), + ArithOp::FloatCompare { a, b } => sexp::list(&[A("fcmp"), A(a), A(b)]), + ArithOp::FloatRangeTest { val, a: start, b: end } => sexp::list(&[A("frcmp"), 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)]) + if min.is_imm_equal((0f64).to_bits()) && max.is_imm_equal(f64::MAX.to_bits()) { + sexp::list(&[A("frng"), A(dst)]) } else if min.is_imm_equal(0) { - sexp::list(&[A("rngf"), A(dst), A(max)]) + sexp::list(&[A("frng"), A(dst), A(max)]) } else { - sexp::list(&[A("rngf"), A(dst), A(min), A(max)]) + sexp::list(&[A("frng"), 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::FloatAdd { dst, a, b } => to_sexp_2_or_3("fadd", dst, a, b), + ArithOp::FloatSub { dst, a, b } => to_sexp_2_or_3("fsub", dst, a, b), + ArithOp::FloatMul { dst, a, b } => to_sexp_2_or_3("fmul", dst, a, b), ArithOp::FloatDiv { dst, rem, a, div } => { if rem.is_discard() { - to_sexp_2_or_3("divf", dst, a, div) + to_sexp_2_or_3("fdiv", dst, a, div) } else { if &dst.as_rd() == a { - sexp::list(&[A("divrf"), A(dst), A(rem), A(div)]) + sexp::list(&[A("fdivr"), A(dst), A(rem), A(div)]) } else { - sexp::list(&[A("divrf"), A(dst), A(rem), A(a), A(div)]) + sexp::list(&[A("fdivr"), A(dst), A(rem), A(a), A(div)]) } } } - ArithOp::FloatMod { dst, a, div } => to_sexp_2_or_3("modf", dst, a, div), + ArithOp::FloatMod { dst, a, div } => to_sexp_2_or_3("fmod", 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), @@ -507,7 +730,31 @@ impl OpTrait for ArithOp { 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 + ArithOp::Abs { dst, a } => to_sexp_1_or_2("abs", dst, a), + ArithOp::Sgn { dst, a } => to_sexp_1_or_2("sgn", dst, a), + ArithOp::Pow { dst, a, pow } => to_sexp_2_or_3("pow", dst, a, pow), + ArithOp::FloatPow { dst, a, pow } => to_sexp_2_or_3("fpow", dst, a, pow), + ArithOp::FloatRoot { dst, a, root } => to_sexp_2_or_3("froot", dst, a, root), + ArithOp::FloatHyp { dst, a, b } => to_sexp_2_or_3("fhyp", dst, a, b), + ArithOp::FloatAbs { dst, a } => to_sexp_1_or_2("fabs", dst, a), + ArithOp::FloatSgn { dst, a } => to_sexp_1_or_2("fsgn", dst, a), + ArithOp::FloatSin { dst, a } => to_sexp_1_or_2("fsin", dst, a), + ArithOp::FloatAsin { dst, a } => to_sexp_1_or_2("fasin", dst, a), + ArithOp::FloatCos { dst, a } => to_sexp_1_or_2("fcos", dst, a), + ArithOp::FloatAcos { dst, a } => to_sexp_1_or_2("facos", dst, a), + ArithOp::FloatTan { dst, a } => to_sexp_1_or_2("ftan", dst, a), + ArithOp::FloatAtan { dst, a } => to_sexp_1_or_2("fatan", dst, a), + ArithOp::FloatAtan2 { dst, x, y } => to_sexp_2_or_3("fatan2", dst, x, y), + ArithOp::FloatCot { dst, a } => to_sexp_1_or_2("fcot", dst, a), + ArithOp::FloatAcot { dst, a } => to_sexp_1_or_2("facot", dst, a), + ArithOp::FloatHypSin { dst, a } => to_sexp_1_or_2("fsinh", dst, a), + ArithOp::FloatHypAsin { dst, a } => to_sexp_1_or_2("fasinh", dst, a), + ArithOp::FloatHypCos { dst, a } => to_sexp_1_or_2("fcosh", dst, a), + ArithOp::FloatHypAcos { dst, a } => to_sexp_1_or_2("facosh", dst, a), + ArithOp::FloatHypTan { dst, a } => to_sexp_1_or_2("ftanh", dst, a), + ArithOp::FloatHypAtan { dst, a } => to_sexp_1_or_2("fatanh", dst, a), + ArithOp::FloatHypCot { dst, a } => to_sexp_1_or_2("fcoth", dst, a), + ArithOp::FloatHypAcot { dst, a } => to_sexp_1_or_2("facoth", dst, a), } } } diff --git a/crsn_arith/src/lib.rs b/crsn_arith/src/lib.rs index 146fb98..045c482 100644 --- a/crsn_arith/src/lib.rs +++ b/crsn_arith/src/lib.rs @@ -1,8 +1,13 @@ +#[macro_use] +extern crate log; + use crsn::asm::error::CrsnError; use crsn::asm::instr::op::OpKind; use crsn::asm::parse::arg_parser::TokenParser; use crsn::module::{CrsnExtension, ParseRes}; use crsn::sexp::SourcePosition; +use crsn::asm::data::literal::Value; +use crate::exec::f2u; mod defs; mod parse; @@ -25,4 +30,19 @@ impl CrsnExtension for ArithOps { fn parse_op<'a>(&self, pos: &SourcePosition, keyword: &str, args: TokenParser<'a>) -> Result, CrsnError> { parse::parse(pos, keyword, args) } + + /// Get value of an extension-provided constant. + /// This constant may be an object handle, or a constant value used as argument in some other instruction. + fn get_constant_value<'a>(&self, name: &str) -> Option + { + use std::f64::consts; + match name { + "PI" => Some(f2u(consts::PI)), + "PI_2" => Some(f2u(consts::FRAC_PI_2)), + "TAU" => Some(f2u(consts::TAU)), + "E" => Some(f2u(consts::E)), + // TODO more?... + _ => None + } + } } diff --git a/crsn_arith/src/parse.rs b/crsn_arith/src/parse.rs index c689991..5a3f275 100644 --- a/crsn_arith/src/parse.rs +++ b/crsn_arith/src/parse.rs @@ -77,6 +77,11 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP ArithOp::Abs { dst, a } } + "sgn" => { + let (dst, a) = args.parse_wr_rd()?; + ArithOp::Sgn { dst, a } + } + "sub" => { let (dst, a, b) = args.parse_wr_rd_rd()?; ArithOp::Sub { dst, a, b } @@ -199,7 +204,7 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP ArithOp::Rbit { dst, src } } - "cmpf" => { + "fcmp" => { let parsed = ArithOp::FloatCompare { a: args.next_rd()?.imm_to_float(), b: args.next_rd()?.imm_to_float(), @@ -305,7 +310,7 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP ArithOp::FloatHyp { dst, a: a.imm_to_float(), - b: a.imm_to_float(), + b: b.imm_to_float(), } } @@ -392,12 +397,17 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP "fabs" => { let (dst, a) = args.parse_wr_rd()?; - ArithOp::FloatAbs { dst, a: f.imm_to_float() } + ArithOp::FloatAbs { dst, a: a.imm_to_float() } + } + + "fsgn" => { + let (dst, a) = args.parse_wr_rd()?; + ArithOp::FloatSgn { dst, a: a.imm_to_float() } } "fsin" => { - let (dst, f) = args.parse_wr_rd()?; - ArithOp::FloatSin { dst, f: f.imm_to_float() } + let (dst, a) = args.parse_wr_rd()?; + ArithOp::FloatSin { dst, a: a.imm_to_float() } } "fasin" => { @@ -406,8 +416,8 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP } "fcos" => { - let (dst, f) = args.parse_wr_rd()?; - ArithOp::FloatCos { dst, f: f.imm_to_float() } + let (dst, a) = args.parse_wr_rd()?; + ArithOp::FloatCos { dst, a: a.imm_to_float() } } "facos" => { @@ -416,8 +426,8 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP } "ftan" => { - let (dst, f) = args.parse_wr_rd()?; - ArithOp::FloatTan { dst, f: f.imm_to_float() } + let (dst, a) = args.parse_wr_rd()?; + ArithOp::FloatTan { dst, a: a.imm_to_float() } } "fatan" => { @@ -435,8 +445,8 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP } "fcot" => { - let (dst, f) = args.parse_wr_rd()?; - ArithOp::FloatCot { dst, f: f.imm_to_float() } + let (dst, a) = args.parse_wr_rd()?; + ArithOp::FloatCot { dst, a: a.imm_to_float() } } "facot" => { @@ -444,6 +454,47 @@ pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenP ArithOp::FloatAcot { dst, a: a.imm_to_float() } } + /* hyperbolic */ + "fsinh" => { + let (dst, a) = args.parse_wr_rd()?; + ArithOp::FloatHypSin { dst, a: a.imm_to_float() } + } + + "fasinh" => { + let (dst, a) = args.parse_wr_rd()?; + ArithOp::FloatHypAsin { dst, a: a.imm_to_float() } + } + + "fcosh" => { + let (dst, a) = args.parse_wr_rd()?; + ArithOp::FloatHypCos { dst, a: a.imm_to_float() } + } + + "facosh" => { + let (dst, a) = args.parse_wr_rd()?; + ArithOp::FloatHypAcos { dst, a: a.imm_to_float() } + } + + "ftanh" => { + let (dst, a) = args.parse_wr_rd()?; + ArithOp::FloatHypTan { dst, a: a.imm_to_float() } + } + + "fatanh" => { + let (dst, a) = args.parse_wr_rd()?; + ArithOp::FloatHypAtan { dst, a: a.imm_to_float() } + } + + "fcoth" => { + let (dst, a) = args.parse_wr_rd()?; + ArithOp::FloatHypCot { dst, a: a.imm_to_float() } + } + + "facoth" => { + let (dst, a) = args.parse_wr_rd()?; + ArithOp::FloatHypAcot { 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 { diff --git a/examples/screen_trig.csn b/examples/screen_trig.csn new file mode 100644 index 0000000..2915fa8 --- /dev/null +++ b/examples/screen_trig.csn @@ -0,0 +1,34 @@ +( + ; mouse over the image to draw circles + (sc-init 800 600) + (sc-opt SCREEN_AUTO_BLIT 0) + + (:loop) + (sc-poll) + (sc-mouse r4 r5 (ov? (j :loop))) + (itf r4) + (itf r5) + + (ld r0 0.0) + (def RADIUS 50.0) + (:circle) + (fsin r1 r0) + (fcos r2 r0) + + (fmul r1 RADIUS) + (fmul r2 RADIUS) + + (fadd r1 r4) + (fadd r2 r5) + + (fti r1) + (fti r2) + (sc-px r1 r2 #66ff00) + (fadd r0 0.1) ; make lower for a smoother circle + (fcmp r0 TAU + (ge? + (sc-blit) + (j :loop))) + (j :circle) + (j :loop) +)