use crsn::asm::data::{Rd, Wr, DataDispEquals}; use crsn::asm::error::CrsnError; 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, FloatToIntMode}; pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result, CrsnError> { Ok(ParseRes::ext(match keyword { "cmp" => { let parsed = ArithOp::Compare { a: args.next_rd()?, b: args.next_rd()? }; args.ensure_empty("two input arguments")?; parsed } "rcmp" => { let parsed = ArithOp::RangeTest { val: args.next_rd()?, a: args.next_rd()?, b: args.next_rd()? }; args.ensure_empty("3 arguments (value, min, max)")?; parsed } "tst" => { let arg = args.next_rd()?; args.ensure_empty("1 input argument")?; ArithOp::Test { a: arg } } "rng" => { let parsed = match args.len() { 1 => { ArithOp::Rng { dst: args.next_wr()?, min: Rd::new_imm(0), max: Rd::new_imm(u64::MAX), } } 2 => { ArithOp::Rng { dst: args.next_wr()?, min: Rd::new_imm(0), max: args.next_rd()?, } } 3 => { ArithOp::Rng { dst: args.next_wr()?, min: args.next_rd()?, max: args.next_rd()?, } } _ => { 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 } "inc" => { let (dst, a) = args.parse_wr_rd()?; ArithOp::Add { dst, a, b: Rd::new_imm(1) } } "dec" => { let (dst, a) = args.parse_wr_rd()?; ArithOp::Sub { dst, a, b: Rd::new_imm(1) } } "add" => { let (dst, a, b) = args.parse_wr_rd_rd()?; 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 } } "mul" => { let (dst, a, b) = args.parse_wr_rd_rd()?; 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 => { let dst = args.next_rdwr()?; let rem = args.next_wr()?; let div = args.next_rd()?; ArithOp::Div { dst: dst.wr(), rem, a: dst.rd(), div, } } 4 => { ArithOp::Div { dst: args.next_wr()?, rem: args.next_wr()?, a: args.next_rd()?, div: args.next_rd()?, } } _ => { return Err(CrsnError::Parse("DivR requires 3 or 4 arguments".into(), op_pos.clone())); } } } "div" => { let (dst, a, div) = args.parse_wr_rd_rd()?; ArithOp::Div { dst, rem: Wr::discard(), a, div } } "mod" => { let (dst, a, div) = args.parse_wr_rd_rd()?; ArithOp::Mod { dst, a, div } } "and" => { let (dst, a, b) = args.parse_wr_rd_rd()?; ArithOp::And { dst, a, b } } "or" => { let (dst, a, b) = args.parse_wr_rd_rd()?; ArithOp::Or { dst, a, b } } "xor" => { let (dst, a, b) = args.parse_wr_rd_rd()?; ArithOp::Xor { dst, a, b } } "cpl" => { let (dst, a) = args.parse_wr_rd()?; ArithOp::Cpl { dst, a } } "rol" => { let (dst, a, n) = args.parse_wr_rd_rd_or_n(1)?; ArithOp::Rol { dst, a, n } } "ror" => { let (dst, a, n) = args.parse_wr_rd_rd_or_n(1)?; ArithOp::Ror { dst, a, n } } "lsl" | "asl" => { let (dst, a, n) = args.parse_wr_rd_rd_or_n(1)?; ArithOp::Lsl { dst, a, n } } "lsr" => { let (dst, a, n) = args.parse_wr_rd_rd_or_n(1)?; ArithOp::Lsr { dst, a, n } } "asr" => { let (dst, a, n) = args.parse_wr_rd_rd_or_n(1)?; ArithOp::Asr { dst, a, n } } "sw32" => { let (dst, src) = args.parse_wr_rd()?; ArithOp::Sw32 { dst, src } } "sw16" => { let (dst, src) = args.parse_wr_rd()?; ArithOp::Sw16 { dst, src } } "sw8" => { let (dst, src) = args.parse_wr_rd()?; ArithOp::Sw8 { dst, src } } "rev" => { let (dst, src) = args.parse_wr_rd()?; ArithOp::Rev { dst, src } } "rbit" => { let (dst, src) = args.parse_wr_rd()?; 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 { return Err(CrsnError::Parse( "Invalid offsets - permissible formats are (RW:src_offs) and (Wr Rd:src_offs) ".into(), op_pos.clone())); } return Ok(ParseRes::ext(ArithOp::Clz { dst, src, mask })); } if let Some((dst, src, mask)) = args.parse_masked_wr_rd(other, "clo")? { if !dst.disp_equals(src) && mask.dst_pos != 0 { return Err(CrsnError::Parse( "Invalid offsets - permissible formats are (RW:src_offs) and (Wr Rd:src_offs)".into(), op_pos.clone())); } return Ok(ParseRes::ext(ArithOp::Clo { dst, src, mask })); } if let Some((dst, src, mask)) = args.parse_masked_wr_rd(other, "se")? { if mask.src_pos != 0 || mask.dst_pos != 0 { return Err(CrsnError::Parse( "Offsets do not make sense for SignExtend".into(), op_pos.clone())); } return Ok(ParseRes::ext(ArithOp::SignExtend { dst, src, mask })); } return Ok(ParseRes::Unknown(args)); } })) }