use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AvrOpcode {
ADD,
ADC,
ADIW,
SUB,
SUBI,
SBC,
SBCI,
SBIW,
INC,
DEC,
MUL,
MULS,
MULSU,
AND,
ANDI,
OR,
ORI,
EOR,
COM,
NEG,
SBR,
CBR,
LSL,
LSR,
ROL,
ROR,
ASR,
SWAP,
RJMP,
IJMP,
EIJMP,
JMP,
RCALL,
ICALL,
EICALL,
CALL,
RET,
RETI,
CPSE,
SBRC,
SBRS,
SBIC,
SBIS,
BRBC,
BRBS,
MOV,
MOVW,
LDI,
LD,
ST,
LDS,
STS,
LD_X,
LD_XP,
LD_XM,
ST_X,
ST_XP,
ST_XM,
LD_Y,
LD_YP,
LD_YM,
ST_Y,
ST_YP,
ST_YM,
LD_Z,
LD_ZP,
LD_ZM,
ST_Z,
ST_ZP,
ST_ZM,
LPM,
LPM_Z,
LPM_ZP,
ELPM,
ELPM_Z,
ELPM_ZP,
SPM,
SPM_ZP,
IN,
OUT,
PUSH,
POP,
SBI,
CBI,
LBL,
BLD,
BSET,
BCLR,
BST,
BLD_G,
SEC,
CLC,
SEN,
CLN,
SEZ,
CLZ,
SEI,
CLI,
SES,
CLS,
SEV,
CLV,
SET,
CLT,
SEH,
CLH,
NOP,
SLEEP,
WDR,
BREAK,
}
#[derive(Debug, Clone)]
pub struct AvrInstrDesc {
pub opcode: AvrOpcode,
pub mnemonic: &'static str,
pub is_terminator: bool,
pub is_branch: bool,
pub is_call: bool,
pub is_return: bool,
pub may_load: bool,
pub may_store: bool,
pub has_side_effects: bool,
pub is_compare: bool,
pub is_commutative: bool,
pub size_bytes: u8,
pub cycles: u8,
}
pub struct AvrInstrInfo {
desc_map: HashMap<AvrOpcode, AvrInstrDesc>,
}
impl AvrInstrInfo {
pub fn new() -> Self {
let mut info = AvrInstrInfo {
desc_map: HashMap::new(),
};
info.register_all();
info
}
pub fn get_desc(&self, opcode: AvrOpcode) -> Option<&AvrInstrDesc> {
self.desc_map.get(&opcode)
}
pub fn is_terminator(&self, opcode: AvrOpcode) -> bool {
self.desc_map
.get(&opcode)
.map_or(false, |d| d.is_terminator)
}
pub fn is_branch(&self, opcode: AvrOpcode) -> bool {
self.desc_map.get(&opcode).map_or(false, |d| d.is_branch)
}
pub fn is_call(&self, opcode: AvrOpcode) -> bool {
self.desc_map.get(&opcode).map_or(false, |d| d.is_call)
}
fn add(&mut self, desc: AvrInstrDesc) {
self.desc_map.insert(desc.opcode, desc);
}
fn register_all(&mut self) {
self.add(AvrInstrDesc {
opcode: AvrOpcode::ADD,
mnemonic: "add",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: true,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::ADC,
mnemonic: "adc",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: true,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::ADIW,
mnemonic: "adiw",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::SUB,
mnemonic: "sub",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::SUBI,
mnemonic: "subi",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::SBC,
mnemonic: "sbc",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::SBCI,
mnemonic: "sbci",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::SBIW,
mnemonic: "sbiw",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::INC,
mnemonic: "inc",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::DEC,
mnemonic: "dec",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::MUL,
mnemonic: "mul",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: true,
size_bytes: 2,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::MULS,
mnemonic: "muls",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: true,
size_bytes: 2,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::MULSU,
mnemonic: "mulsu",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::AND,
mnemonic: "and",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: true,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::ANDI,
mnemonic: "andi",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::OR,
mnemonic: "or",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: true,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::ORI,
mnemonic: "ori",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::EOR,
mnemonic: "eor",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: true,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::COM,
mnemonic: "com",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::NEG,
mnemonic: "neg",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::SBR,
mnemonic: "sbr",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::CBR,
mnemonic: "cbr",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::LSL,
mnemonic: "lsl",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::LSR,
mnemonic: "lsr",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::ROL,
mnemonic: "rol",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::ROR,
mnemonic: "ror",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::ASR,
mnemonic: "asr",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::SWAP,
mnemonic: "swap",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::RJMP,
mnemonic: "rjmp",
is_terminator: true,
is_branch: true,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::IJMP,
mnemonic: "ijmp",
is_terminator: true,
is_branch: true,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::EIJMP,
mnemonic: "eijmp",
is_terminator: true,
is_branch: true,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::JMP,
mnemonic: "jmp",
is_terminator: true,
is_branch: true,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 4,
cycles: 3,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::RCALL,
mnemonic: "rcall",
is_terminator: false,
is_branch: false,
is_call: true,
is_return: false,
may_load: false,
may_store: true,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 3,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::ICALL,
mnemonic: "icall",
is_terminator: false,
is_branch: false,
is_call: true,
is_return: false,
may_load: false,
may_store: true,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 3,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::EICALL,
mnemonic: "eicall",
is_terminator: false,
is_branch: false,
is_call: true,
is_return: false,
may_load: false,
may_store: true,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 4,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::CALL,
mnemonic: "call",
is_terminator: false,
is_branch: false,
is_call: true,
is_return: false,
may_load: false,
may_store: true,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 4,
cycles: 4,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::RET,
mnemonic: "ret",
is_terminator: true,
is_branch: false,
is_call: false,
is_return: true,
may_load: true,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 4,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::RETI,
mnemonic: "reti",
is_terminator: true,
is_branch: false,
is_call: false,
is_return: true,
may_load: true,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 4,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::CPSE,
mnemonic: "cpse",
is_terminator: false,
is_branch: true,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: true,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::SBRC,
mnemonic: "sbrc",
is_terminator: false,
is_branch: true,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::SBRS,
mnemonic: "sbrs",
is_terminator: false,
is_branch: true,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::SBIC,
mnemonic: "sbic",
is_terminator: false,
is_branch: true,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::SBIS,
mnemonic: "sbis",
is_terminator: false,
is_branch: true,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::BRBC,
mnemonic: "brbc",
is_terminator: false,
is_branch: true,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::BRBS,
mnemonic: "brbs",
is_terminator: false,
is_branch: true,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::MOV,
mnemonic: "mov",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::MOVW,
mnemonic: "movw",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::LDI,
mnemonic: "ldi",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::LD,
mnemonic: "ld",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: true,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::ST,
mnemonic: "st",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: true,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::LDS,
mnemonic: "lds",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: true,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 4,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::STS,
mnemonic: "sts",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: true,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 4,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::IN,
mnemonic: "in",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: true,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::OUT,
mnemonic: "out",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: true,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::PUSH,
mnemonic: "push",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: true,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::POP,
mnemonic: "pop",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: true,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::SBI,
mnemonic: "sbi",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: true,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::CBI,
mnemonic: "cbi",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: true,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 2,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::BSET,
mnemonic: "bset",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::BCLR,
mnemonic: "bclr",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::NOP,
mnemonic: "nop",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: false,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::SLEEP,
mnemonic: "sleep",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: true,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::WDR,
mnemonic: "wdr",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: true,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
self.add(AvrInstrDesc {
opcode: AvrOpcode::BREAK,
mnemonic: "break",
is_terminator: false,
is_branch: false,
is_call: false,
is_return: false,
may_load: false,
may_store: false,
has_side_effects: true,
is_compare: false,
is_commutative: false,
size_bytes: 2,
cycles: 1,
});
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_all_opcodes_registered() {
let info = AvrInstrInfo::new();
assert!(info.get_desc(AvrOpcode::ADD).is_some());
assert!(info.get_desc(AvrOpcode::NOP).is_some());
}
#[test]
fn test_terminators() {
let info = AvrInstrInfo::new();
assert!(info.is_terminator(AvrOpcode::RJMP));
assert!(info.is_terminator(AvrOpcode::RET));
assert!(!info.is_terminator(AvrOpcode::ADD));
}
#[test]
fn test_branches() {
let info = AvrInstrInfo::new();
assert!(info.is_branch(AvrOpcode::BRBC));
assert!(info.is_branch(AvrOpcode::SBRS));
assert!(!info.is_branch(AvrOpcode::MOV));
}
#[test]
fn test_calls() {
let info = AvrInstrInfo::new();
assert!(info.is_call(AvrOpcode::CALL));
assert!(info.is_call(AvrOpcode::RCALL));
assert!(!info.is_call(AvrOpcode::RJMP));
}
#[test]
fn test_loads_stores() {
let info = AvrInstrInfo::new();
let ld = info.get_desc(AvrOpcode::LD).unwrap();
assert!(ld.may_load);
assert!(!ld.may_store);
let st = info.get_desc(AvrOpcode::ST).unwrap();
assert!(st.may_store);
assert!(!st.may_load);
}
#[test]
fn test_instruction_sizes() {
let info = AvrInstrInfo::new();
let add = info.get_desc(AvrOpcode::ADD).unwrap();
assert_eq!(add.size_bytes, 2);
let call = info.get_desc(AvrOpcode::CALL).unwrap();
assert_eq!(call.size_bytes, 4);
}
#[test]
fn test_arithmetic_mnemonics() {
let info = AvrInstrInfo::new();
assert_eq!(info.get_desc(AvrOpcode::ADD).unwrap().mnemonic, "add");
assert_eq!(info.get_desc(AvrOpcode::MUL).unwrap().mnemonic, "mul");
assert_eq!(info.get_desc(AvrOpcode::INC).unwrap().mnemonic, "inc");
}
#[test]
fn test_branch_mnemonics() {
let info = AvrInstrInfo::new();
assert_eq!(info.get_desc(AvrOpcode::RJMP).unwrap().mnemonic, "rjmp");
assert_eq!(info.get_desc(AvrOpcode::IJMP).unwrap().mnemonic, "ijmp");
}
#[test]
fn test_data_transfer_mnemonics() {
let info = AvrInstrInfo::new();
assert_eq!(info.get_desc(AvrOpcode::MOV).unwrap().mnemonic, "mov");
assert_eq!(info.get_desc(AvrOpcode::LDI).unwrap().mnemonic, "ldi");
assert_eq!(info.get_desc(AvrOpcode::PUSH).unwrap().mnemonic, "push");
}
#[test]
fn test_commutative_ops() {
let info = AvrInstrInfo::new();
assert!(info.get_desc(AvrOpcode::ADD).unwrap().is_commutative);
assert!(!info.get_desc(AvrOpcode::SUB).unwrap().is_commutative);
}
#[test]
fn test_compare_ops() {
let info = AvrInstrInfo::new();
assert!(info.get_desc(AvrOpcode::CPSE).unwrap().is_compare);
}
#[test]
fn test_side_effects() {
let info = AvrInstrInfo::new();
assert!(info.get_desc(AvrOpcode::SLEEP).unwrap().has_side_effects);
assert!(info.get_desc(AvrOpcode::WDR).unwrap().has_side_effects);
assert!(info.get_desc(AvrOpcode::BREAK).unwrap().has_side_effects);
assert!(!info.get_desc(AvrOpcode::ADD).unwrap().has_side_effects);
}
#[test]
fn test_call_has_store_side_effect() {
let info = AvrInstrInfo::new();
assert!(info.get_desc(AvrOpcode::CALL).unwrap().may_store);
}
#[test]
fn test_ret_is_terminator() {
let info = AvrInstrInfo::new();
assert!(info.is_terminator(AvrOpcode::RET));
assert!(info.is_terminator(AvrOpcode::RETI));
}
#[test]
fn test_default_not_terminator() {
let info = AvrInstrInfo::new();
assert!(!info.is_terminator(AvrOpcode::ADD));
}
}