forked from MightyPork/crsn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
542 lines
16 KiB
542 lines
16 KiB
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<ParseRes<'a, OpKind>, 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 }
|
|
}
|
|
|
|
"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 }
|
|
}
|
|
|
|
"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 }
|
|
}
|
|
|
|
"fcmp" => {
|
|
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: b.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: a.imm_to_float() }
|
|
}
|
|
|
|
"fsgn" => {
|
|
let (dst, a) = args.parse_wr_rd()?;
|
|
ArithOp::FloatSgn { dst, a: a.imm_to_float() }
|
|
}
|
|
|
|
"fsin" => {
|
|
let (dst, a) = args.parse_wr_rd()?;
|
|
ArithOp::FloatSin { dst, a: a.imm_to_float() }
|
|
}
|
|
|
|
"fasin" => {
|
|
let (dst, a) = args.parse_wr_rd()?;
|
|
ArithOp::FloatAsin { dst, a: a.imm_to_float() }
|
|
}
|
|
|
|
"fcos" => {
|
|
let (dst, a) = args.parse_wr_rd()?;
|
|
ArithOp::FloatCos { dst, a: a.imm_to_float() }
|
|
}
|
|
|
|
"facos" => {
|
|
let (dst, a) = args.parse_wr_rd()?;
|
|
ArithOp::FloatAcos { dst, a: a.imm_to_float() }
|
|
}
|
|
|
|
"ftan" => {
|
|
let (dst, a) = args.parse_wr_rd()?;
|
|
ArithOp::FloatTan { dst, a: a.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, a) = args.parse_wr_rd()?;
|
|
ArithOp::FloatCot { dst, a: a.imm_to_float() }
|
|
}
|
|
|
|
"facot" => {
|
|
let (dst, a) = args.parse_wr_rd()?;
|
|
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 {
|
|
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));
|
|
}
|
|
}))
|
|
}
|
|
|
|
|