msp430-repl/src/parser/instruction/encoding/secondary_operand.rs

96 lines
3.2 KiB
Rust

// © 2023 John Breaux
//! A [`SecondaryOperand`] contains the second [`Register`], addressing mode, and Extension
//! Word for a [two-operand](Encoding::Double) [instruction]
use super::*;
/// The destination of a [Double](Encoding::Double)
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum SecondaryOperand {
Direct(Register),
Indexed(Register, Number),
Absolute(Number),
// Joke encodings?
Zero,
One,
}
impl SecondaryOperand {
pub fn mode(&self) -> u16 {
use SecondaryOperand::*;
match self {
Direct(_) | Zero => 0,
Indexed(_, _) | Absolute(_) | One => 1 << 7,
}
}
pub fn register(&self) -> Register {
use SecondaryOperand::*;
match self {
Direct(r) | Indexed(r, _) => *r,
Absolute(_) => Register::sr,
Zero | One => Register::cg,
}
}
/// This is the only way to have an extension word
pub fn ext_word(&self) -> Option<u16> {
use SecondaryOperand::*;
match self {
Indexed(_, w) | Absolute(w) => Some((*w).into()),
_ => None,
}
}
}
impl Parsable for SecondaryOperand {
// Separator
// - Register => Direct
// - Number => Indexed
// - OpenIdx
// - Register
// - CloseIdx
// - Absolute
// - Number
// - Immediate
// - Number == 0, 1
fn parse<'text, T>(p: &Parser, stream: &mut T) -> Result<Self, crate::Error>
where T: crate::TokenStream<'text> {
use SecondaryOperand::*;
stream.allow(Type::Separator);
// Try parsing as Register (Direct)
if let Some(r) = Register::try_parse(p, stream)? {
return Ok(Self::Direct(r));
}
// Try parsing as Number (Indexed)
if let Some(idx) = Number::try_parse(p, stream)? {
stream.expect(Type::LParen)?;
let reg = Register::parse(p, stream)?;
stream.expect(Type::RParen)?;
return Ok(Self::Indexed(reg, idx));
}
// Type::Register and Type::Number are included here to make error messages clearer.
// their inclusion will cause a negligible slowdown when the next token is not a prefix marker
// (a failure condition) but should not match a token
let token = stream.expect_any_of([Type::Absolute, Type::Immediate, Type::Register, Type::Number])?;
Ok(match token.variant() {
Type::Absolute => Absolute(Number::parse(p, stream)?),
Type::Immediate => match Number::parse(p, stream)?.into() {
0 => Zero,
1 => One,
n => Err(Error::FatSecondaryImmediate(n as isize).context(stream.context()))?,
},
_ => unreachable!("Token {token:?} passed expectation but failed match!"),
})
}
}
impl Display for SecondaryOperand {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Direct(r) => Display::fmt(r, f),
Self::Indexed(r, idx) => write!(f, "{idx}({r})"),
Self::Absolute(n) => write!(f, "&{n}"),
Self::Zero => Display::fmt("#0", f),
Self::One => Display::fmt("#1", f),
}
}
}