add (cas), (casXX), and (bfcas)

This commit is contained in:
2020-10-28 22:48:25 +01:00
parent 4e67ac291f
commit d0d4f1c15e
8 changed files with 130 additions and 0 deletions
+30
View File
@@ -291,6 +291,36 @@ impl<'a> TokenParser<'a> {
}
}
/// Parse (RdWr, Rd, Rd) with an optional mask
pub fn parse_masked_rdwr_rd_rd(&mut self, keyword: &str, prefix: &str) -> Result<Option<(RdWr, Rd, Rd, BitMask)>, CrsnError> {
if let Some(s) = keyword.strip_prefix(prefix) {
let width = if s.is_empty() {
(std::mem::size_of::<Value>() as u32) * 8
} else {
s.parse().err_pos(self.start_pos)?
};
if self.len() == 3 {
let (rw, dst_pos) = self.next_rdwr_offset()?;
let (r1, src_pos) = self.next_rd_offset()?;
let (r2, src2_pos) = self.next_rd_offset()?;
let mask = BitMask {
width,
dst_pos,
src_pos,
src2_pos,
};
mask.validate(self.start_pos)?;
Ok(Some((rw, r1, r2, mask)))
} else {
Err(CrsnError::Parse("Instruction needs 3 (RW,Rd,Rd) arguments!".into(), self.start_pos.clone()))
}
} else {
Ok(None)
}
}
/// Parse combining binary instruction operands (i.e. add) without masks
/// Accepts (Wr, Rd, Rd) and (RdWr, Rd)
pub fn parse_wr_rd_rd(&mut self) -> Result<(Wr, Rd, Rd), CrsnError> {
+2
View File
@@ -164,6 +164,8 @@ pub enum BuiltinOp {
LoadSequence { dst: Wr, value: LdsValue },
/// Swap two registers
Exchange { a: RdWr, b: RdWr, mask: BitMask },
/// Swap if equal to a pattern
CompareSwap { dst: RdWr, expected: Rd, src: Rd, mask: BitMask },
/// Store runtime status to a register
StoreFlags { dst: Wr },
/// Load runtime status from a register
+22
View File
@@ -173,6 +173,28 @@ impl OpTrait for BuiltinOp {
state.write(b, bb2)?;
}
}
BuiltinOp::CompareSwap { dst, expected, src, mask: slice } => {
state.clear_status();
let old = state.read(dst)?;
let exp = state.read(expected)?;
if slice.is_full() {
if old == exp {
let new = state.read(src)?;
state.write(dst, new)?;
state.set_flag(Flag::Equal, true);
}
} else {
let ones: u64 = (1 << slice.width) - 1;
if (old & (ones << slice.dst_pos)) == (exp & (ones << slice.src_pos)) {
let new = state.read(src)?;
let replacement = (old & !(ones << slice.dst_pos)) | (((new & (ones << slice.src2_pos)) >> slice.src2_pos) << slice.dst_pos);
state.write(dst, replacement)?;
state.set_flag(Flag::Equal, true);
}
}
}
BuiltinOp::StoreFlags { dst } => {
let packed = state.frame.status.store();
state.write(dst, packed)?;
+13
View File
@@ -289,6 +289,10 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok
return Ok(ParseRes::builtin(BuiltinOp::Exchange { a, b, mask }));
}
if let Some((dst, expected, src, mask)) = args.parse_masked_rdwr_rd_rd(other, "cas")? {
return Ok(ParseRes::builtin(BuiltinOp::CompareSwap { dst, expected, src, mask }));
}
if other.starts_with(':') {
BuiltinOp::Label(parse_label_str(other, &op_pos)?)
} else {
@@ -389,6 +393,13 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp {
sexp::list(&[A(format!("xch{}", mask.width)), AM(a, mask.dst_pos), AM(b, mask.src_pos)])
}
},
BuiltinOp::CompareSwap { dst, expected, src, mask } => {
if mask.is_full() {
sexp::list(&[A("cas"), A(dst), A(expected), A(src)])
} else {
sexp::list(&[A(format!("cas{}", mask.width)), AM(dst, mask.dst_pos), AM(expected, mask.src_pos), AM(src, mask.src2_pos)])
}
},
BuiltinOp::StoreFlags { dst } => sexp::list(&[A("stf"), A(dst)]),
BuiltinOp::LoadFlags { src } => sexp::list(&[A("ldf"), A(src)]),
BuiltinOp::LoadSequence { dst, value } => {
@@ -474,6 +485,8 @@ mod test {
("(xch r0 r1)", "(xch r0 r1)"),
("(xch32 r0 r1)", "(xch32 r0 r1)"),
("(xch32 r0:8 r1:16)", "(xch32 r0:8 r1:16)"),
("(cas r0 r1 r2)", "(cas r0 r1 r2)"),
("(cas8 r0:8 r1:16 r2:24)", "(cas8 r0:8 r1:16 r2:24)"),
("(ld r0 r0)", "(ld r0 r0)"),
("(ld8 r0 r1)", "(ld8 r0 r1)"),
("(ld16 r0 r1)", "(ld16 r0 r1)"),