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; 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::immediate(0), max: Rd::immediate(u64::MAX), } } 2 => { ArithOp::Rng { dst: args.next_wr()?, min: Rd::immediate(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::immediate(1) } } "dec" => { let (dst, a) = args.parse_wr_rd()?; ArithOp::Sub { dst, a, b: Rd::immediate(1) } } "add" => { let (dst, a, b) = args.parse_wr_rd_rd()?; ArithOp::Add { dst, a, b } } "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 } } "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 } } 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)); } })) }