use crsn::asm::data::{Rd, Wr}; 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; use crsn::builtin::defs::BitSlice; pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result, CrsnError> { Ok(ParseRes::ext(match keyword { "cmp" => { ArithOp::Compare { a: args.next_rd()?, b: args.next_rd()?, } } "rcmp" => { ArithOp::RangeTest { val: args.next_rd()?, a: args.next_rd()?, b: args.next_rd()?, } } "tst" => { let arg = args.next_rd()?; ArithOp::Test { a: arg } } "rng" => { 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())); } } } "inc" => { let dst = args.next_rdwr()?; ArithOp::Add { dst: dst.wr(), a: dst.rd(), b: Rd::immediate(1), } } "dec" => { let dst = args.next_rdwr()?; ArithOp::Sub { dst: dst.wr(), a: dst.rd(), b: Rd::immediate(1), } } "add" => { match args.len() { 3 => { ArithOp::Add { dst: args.next_wr()?, a: args.next_rd()?, b: args.next_rd()?, } } 2 => { let dst = args.next_rdwr()?; ArithOp::Add { dst: dst.wr(), a: dst.rd(), b: args.next_rd()?, } } _ => { return Err(CrsnError::Parse("Add requires 2 or 3 arguments".into(), op_pos.clone())); } } } "sub" => { match args.len() { 3 => { ArithOp::Sub { dst: args.next_wr()?, a: args.next_rd()?, b: args.next_rd()?, } } 2 => { let dst = args.next_rdwr()?; ArithOp::Sub { dst: dst.wr(), a: dst.rd(), b: args.next_rd()?, } } _ => { return Err(CrsnError::Parse("Sub requires 2 or 3 arguments".into(), op_pos.clone())); } } } "mul" => { match args.len() { 3 => { ArithOp::Mul { dst: args.next_wr()?, a: args.next_rd()?, b: args.next_rd()?, } } 2 => { let dst = args.next_rdwr()?; ArithOp::Mul { dst: dst.wr(), a: dst.rd(), b: args.next_rd()?, } } _ => { return Err(CrsnError::Parse("Mul requires 2 or 3 arguments".into(), op_pos.clone())); } } } "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" => { match args.len() { 3 => { ArithOp::Div { dst: args.next_wr()?, rem: Wr::discard(), a: args.next_rd()?, div: args.next_rd()?, } } 2 => { let dst = args.next_rdwr()?; let div = args.next_rd()?; ArithOp::Div { dst: dst.wr(), rem: Wr::discard(), a: dst.rd(), div, } } _ => { return Err(CrsnError::Parse("Div requires 2 or 3 arguments".into(), op_pos.clone())); } } } "mod" => { match args.len() { 3 => { ArithOp::Mod { dst: args.next_wr()?, a: args.next_rd()?, div: args.next_rd()?, } } 2 => { let dst = args.next_rdwr()?; let div = args.next_rd()?; ArithOp::Mod { dst: dst.wr(), a: dst.rd(), div, } } _ => { return Err(CrsnError::Parse("Mod requires 2 or 3 arguments".into(), op_pos.clone())); } } } "and" => { match args.len() { 3 => { ArithOp::And { dst: args.next_wr()?, a: args.next_rd()?, b: args.next_rd()?, } } 2 => { let dst = args.next_rdwr()?; ArithOp::And { dst: dst.wr(), a: dst.rd(), b: args.next_rd()?, } } _ => { return Err(CrsnError::Parse("And requires 2 or 3 arguments".into(), op_pos.clone())); } } } "or" => { match args.len() { 3 => { ArithOp::Or { dst: args.next_wr()?, a: args.next_rd()?, b: args.next_rd()?, } } 2 => { let dst = args.next_rdwr()?; ArithOp::Or { dst: dst.wr(), a: dst.rd(), b: args.next_rd()?, } } _ => { return Err(CrsnError::Parse("Or requires 2 or 3 arguments".into(), op_pos.clone())); } } } "xor" => { match args.len() { 3 => { ArithOp::Xor { dst: args.next_wr()?, a: args.next_rd()?, b: args.next_rd()?, } } 2 => { let dst = args.next_rdwr()?; ArithOp::Xor { dst: dst.wr(), a: dst.rd(), b: args.next_rd()?, } } _ => { return Err(CrsnError::Parse("Xor requires 2 or 3 arguments".into(), op_pos.clone())); } } } "cpl" => { match args.len() { 2 => { ArithOp::Cpl { dst: args.next_wr()?, a: args.next_rd()?, } } 1 => { let dst = args.next_rdwr()?; ArithOp::Cpl { dst: dst.wr(), a: dst.rd(), } } _ => { return Err(CrsnError::Parse("Cpl requires 1 or 2 arguments".into(), op_pos.clone())); } } } "rol" => { match args.len() { 3 => { ArithOp::Rol { dst: args.next_wr()?, a: args.next_rd()?, n: args.next_rd()?, } } 2 => { let dst = args.next_rdwr()?; ArithOp::Rol { dst: dst.wr(), a: dst.rd(), n: args.next_rd()?, } } 1 => { let dst = args.next_rdwr()?; ArithOp::Rol { dst: dst.wr(), a: dst.rd(), n: Rd::immediate(1), } } _ => { return Err(CrsnError::Parse("Rol requires 1, 2 or 3 arguments".into(), op_pos.clone())); } } } "ror" => { match args.len() { 3 => { ArithOp::Ror { dst: args.next_wr()?, a: args.next_rd()?, n: args.next_rd()?, } } 2 => { let dst = args.next_rdwr()?; ArithOp::Ror { dst: dst.wr(), a: dst.rd(), n: args.next_rd()?, } } 1 => { let dst = args.next_rdwr()?; ArithOp::Ror { dst: dst.wr(), a: dst.rd(), n: Rd::immediate(1), } } _ => { return Err(CrsnError::Parse("Ror requires 1, 2 or 3 arguments".into(), op_pos.clone())); } } } "lsl" | "asl" => { match args.len() { 3 => { ArithOp::Lsl { dst: args.next_wr()?, a: args.next_rd()?, n: args.next_rd()?, } } 2 => { let dst = args.next_rdwr()?; ArithOp::Lsl { dst: dst.wr(), a: dst.rd(), n: args.next_rd()?, } } 1 => { let dst = args.next_rdwr()?; ArithOp::Lsl { dst: dst.wr(), a: dst.rd(), n: Rd::immediate(1), } } _ => { return Err(CrsnError::Parse("Lsl requires 1, 2 or 3 arguments".into(), op_pos.clone())); } } } "lsr" => { match args.len() { 3 => { ArithOp::Lsr { dst: args.next_wr()?, a: args.next_rd()?, n: args.next_rd()?, } } 2 => { let dst = args.next_rdwr()?; ArithOp::Lsr { dst: dst.wr(), a: dst.rd(), n: args.next_rd()?, } } 1 => { let dst = args.next_rdwr()?; ArithOp::Lsr { dst: dst.wr(), a: dst.rd(), n: Rd::immediate(1), } } _ => { return Err(CrsnError::Parse("Lsr requires 1, 2 or 3 arguments".into(), op_pos.clone())); } } } "asr" => { match args.len() { 3 => { ArithOp::Asr { dst: args.next_wr()?, a: args.next_rd()?, n: args.next_rd()?, } } 2 => { let dst = args.next_rdwr()?; ArithOp::Asr { dst: dst.wr(), a: dst.rd(), n: args.next_rd()?, } } 1 => { let dst = args.next_rdwr()?; ArithOp::Asr { dst: dst.wr(), a: dst.rd(), n: Rd::immediate(1), } } _ => { return Err(CrsnError::Parse("Asr requires 1, 2 or 3 arguments".into(), op_pos.clone())); } } } "sw32" => { match args.len() { 2 => { ArithOp::Sw32 { dst: args.next_wr()?, src: args.next_rd()?, } } 1 => { let dst = args.next_rdwr()?; ArithOp::Sw32 { dst: dst.wr(), src: dst.rd(), } } _ => { return Err(CrsnError::Parse("SW32 requires 1 or 2 arguments".into(), op_pos.clone())); } } } "sw16" => { match args.len() { 2 => { ArithOp::Sw16 { dst: args.next_wr()?, src: args.next_rd()?, } } 1 => { let dst = args.next_rdwr()?; ArithOp::Sw16 { dst: dst.wr(), src: dst.rd(), } } _ => { return Err(CrsnError::Parse("SW16 requires 1 or 2 arguments".into(), op_pos.clone())); } } } "sw8" => { match args.len() { 2 => { ArithOp::Sw8 { dst: args.next_wr()?, src: args.next_rd()?, } } 1 => { let dst = args.next_rdwr()?; ArithOp::Sw8 { dst: dst.wr(), src: dst.rd(), } } _ => { return Err(CrsnError::Parse("SW8 requires 1 or 2 arguments".into(), op_pos.clone())); } } } "rev" => { match args.len() { 2 => { ArithOp::Rev { dst: args.next_wr()?, src: args.next_rd()?, } } 1 => { let dst = args.next_rdwr()?; ArithOp::Rev { dst: dst.wr(), src: dst.rd(), } } _ => { return Err(CrsnError::Parse("REV requires 1 or 2 arguments".into(), op_pos.clone())); } } } "rbit" => { match args.len() { 2 => { ArithOp::Rbit { dst: args.next_wr()?, src: args.next_rd()?, } } 1 => { let dst = args.next_rdwr()?; ArithOp::Rbit { dst: dst.wr(), src: dst.rd(), } } _ => { return Err(CrsnError::Parse("RBIT requires 1 or 2 arguments".into(), op_pos.clone())); } } } other => { if let Some(s) = other.strip_prefix("clz") { if let Some(slice) = BitSlice::parse2(s, op_pos)? { return Ok(ParseRes::ext(match args.len() { 2 => { ArithOp::Clz { dst: args.next_wr()?, src: args.next_rd()?, slice } } 1 => { let dst = args.next_rdwr()?; ArithOp::Clz { dst: dst.wr(), src: dst.rd(), slice } } _ => { return Err(CrsnError::Parse("Clz requires 1 or 2 arguments".into(), op_pos.clone())); } })); } } if let Some(s) = other.strip_prefix("clo") { if let Some(slice) = BitSlice::parse2(s, op_pos)? { return Ok(ParseRes::ext(match args.len() { 2 => { ArithOp::Clo { dst: args.next_wr()?, src: args.next_rd()?, slice } } 1 => { let dst = args.next_rdwr()?; ArithOp::Clo { dst: dst.wr(), src: dst.rd(), slice } } _ => { return Err(CrsnError::Parse("Clz requires 1 or 2 arguments".into(), op_pos.clone())); } })); } } if let Some(s) = other.strip_prefix("se") { if let Some(slice) = BitSlice::parse1(s, op_pos)? { if slice.is_full() { return Err(CrsnError::Parse("Sign extend requires a bit size (< 64)".into(), op_pos.clone())); } return Ok(ParseRes::ext(match args.len() { 2 => { ArithOp::SignExtend { dst: args.next_wr()?, src: args.next_rd()?, slice } } 1 => { let dst = args.next_rdwr()?; ArithOp::SignExtend { dst: dst.wr(), src: dst.rd(), slice } } _ => { return Err(CrsnError::Parse("Sign extend requires 1 or 2 arguments".into(), op_pos.clone())); } })); } } return Ok(ParseRes::Unknown(args)); } })) }