use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ArcOpcode {
ADD,
ADD1,
ADD2,
ADD3,
SUB,
SUB1,
SUB2,
SUB3,
AND,
OR,
XOR,
BIC,
BIC1,
ASL,
ASL1,
ASR,
ASR1,
LSR,
LSR1,
ROR,
MOV,
MOV_S,
MOVHI,
CMP,
RCMP,
LD,
LD_S,
LDB,
LDB_S,
LDW,
LDW_S,
ST,
ST_S,
STB,
STB_S,
STW,
STW_S,
B,
B_S,
BL,
BL_S,
J,
J_S,
JL,
JL_S,
BR,
BNE,
BEQ,
BGT,
BGE,
BLT,
BLE,
BHI,
BHS,
BLO,
BLS,
LP,
FLAG,
SEXB,
SEXW,
EXTB,
EXTW,
ABS,
NEG,
MAX,
MIN,
SWAP,
NORM,
NORMH,
SAT16,
ADDS,
SUBS,
MUL64,
MULU64,
DIV,
BARREL_SHIFTER,
BMSK,
BMSKN,
NOP,
BRK,
SLEEP,
SWI,
RTIE,
}
impl ArcOpcode {
pub fn mnemonic(&self) -> &'static str {
match self {
Self::ADD => "add",
Self::ADD1 => "add1",
Self::ADD2 => "add2",
Self::ADD3 => "add3",
Self::SUB => "sub",
Self::SUB1 => "sub1",
Self::SUB2 => "sub2",
Self::SUB3 => "sub3",
Self::AND => "and",
Self::OR => "or",
Self::XOR => "xor",
Self::BIC => "bic",
Self::BIC1 => "bic1",
Self::ASL => "asl",
Self::ASL1 => "asl1",
Self::ASR => "asr",
Self::ASR1 => "asr1",
Self::LSR => "lsr",
Self::LSR1 => "lsr1",
Self::ROR => "ror",
Self::MOV => "mov",
Self::MOV_S => "mov_s",
Self::MOVHI => "movhi",
Self::CMP => "cmp",
Self::RCMP => "rcmp",
Self::LD => "ld",
Self::LD_S => "ld_s",
Self::LDB => "ldb",
Self::LDB_S => "ldb_s",
Self::LDW => "ldw",
Self::LDW_S => "ldw_s",
Self::ST => "st",
Self::ST_S => "st_s",
Self::STB => "stb",
Self::STB_S => "stb_s",
Self::STW => "stw",
Self::STW_S => "stw_s",
Self::B => "b",
Self::B_S => "b_s",
Self::BL => "bl",
Self::BL_S => "bl_s",
Self::J => "j",
Self::J_S => "j_s",
Self::JL => "jl",
Self::JL_S => "jl_s",
Self::BR => "br",
Self::BNE => "bne",
Self::BEQ => "beq",
Self::BGT => "bgt",
Self::BGE => "bge",
Self::BLT => "blt",
Self::BLE => "ble",
Self::BHI => "bhi",
Self::BHS => "bhs",
Self::BLO => "blo",
Self::BLS => "bls",
Self::LP => "lp",
Self::FLAG => "flag",
Self::SEXB => "sexb",
Self::SEXW => "sexw",
Self::EXTB => "extb",
Self::EXTW => "extw",
Self::ABS => "abs",
Self::NEG => "neg",
Self::MAX => "max",
Self::MIN => "min",
Self::SWAP => "swap",
Self::NORM => "norm",
Self::NORMH => "normh",
Self::SAT16 => "sat16",
Self::ADDS => "adds",
Self::SUBS => "subs",
Self::MUL64 => "mul64",
Self::MULU64 => "mulu64",
Self::DIV => "div",
Self::BARREL_SHIFTER => "barrel_shifter",
Self::BMSK => "bmsk",
Self::BMSKN => "bmskn",
Self::NOP => "nop",
Self::BRK => "brk",
Self::SLEEP => "sleep",
Self::SWI => "swi",
Self::RTIE => "rtie",
}
}
}
#[derive(Debug, Clone)]
pub struct ArcInstrDesc {
pub opcode: ArcOpcode,
pub mnemonic: &'static str,
pub is_terminator: bool,
pub is_branch: bool,
pub is_call: bool,
pub is_return: bool,
pub is_compare: bool,
pub is_move_imm: bool,
pub may_load: bool,
pub may_store: bool,
pub has_side_effects: bool,
pub is_commutative: bool,
pub is_convertible_to_three_address: bool,
pub size_bytes: u32,
pub cycles: u32,
}
pub struct ArcInstrInfo {
desc_map: HashMap<ArcOpcode, ArcInstrDesc>,
}
impl ArcInstrInfo {
pub fn new() -> Self {
let mut info = Self {
desc_map: HashMap::new(),
};
info.register_all();
info
}
pub fn get_desc(&self, opcode: ArcOpcode) -> Option<&ArcInstrDesc> {
self.desc_map.get(&opcode)
}
pub fn is_terminator(&self, opcode: ArcOpcode) -> bool {
self.desc_map
.get(&opcode)
.map(|d| d.is_terminator)
.unwrap_or(false)
}
pub fn is_branch(&self, opcode: ArcOpcode) -> bool {
self.desc_map
.get(&opcode)
.map(|d| d.is_branch)
.unwrap_or(false)
}
pub fn is_call(&self, opcode: ArcOpcode) -> bool {
self.desc_map
.get(&opcode)
.map(|d| d.is_call)
.unwrap_or(false)
}
pub fn may_load(&self, opcode: ArcOpcode) -> bool {
self.desc_map
.get(&opcode)
.map(|d| d.may_load)
.unwrap_or(false)
}
pub fn may_store(&self, opcode: ArcOpcode) -> bool {
self.desc_map
.get(&opcode)
.map(|d| d.may_store)
.unwrap_or(false)
}
fn add(
&mut self,
opcode: ArcOpcode,
is_terminator: bool,
is_branch: bool,
is_call: bool,
is_return: bool,
is_compare: bool,
is_move_imm: bool,
may_load: bool,
may_store: bool,
has_side_effects: bool,
is_commutative: bool,
is_convertible_to_three_address: bool,
size_bytes: u32,
cycles: u32,
) {
self.desc_map.insert(
opcode,
ArcInstrDesc {
opcode,
mnemonic: opcode.mnemonic(),
is_terminator,
is_branch,
is_call,
is_return,
is_compare,
is_move_imm,
may_load,
may_store,
has_side_effects,
is_commutative,
is_convertible_to_three_address,
size_bytes,
cycles,
},
);
}
fn register_all(&mut self) {
self.add(
ArcOpcode::ADD,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
4,
1,
);
self.add(
ArcOpcode::ADD1,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
4,
1,
);
self.add(
ArcOpcode::ADD2,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
4,
1,
);
self.add(
ArcOpcode::ADD3,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
4,
1,
);
self.add(
ArcOpcode::SUB,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
4,
1,
);
self.add(
ArcOpcode::SUB1,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
4,
1,
);
self.add(
ArcOpcode::SUB2,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
4,
1,
);
self.add(
ArcOpcode::SUB3,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
4,
1,
);
self.add(
ArcOpcode::AND,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
4,
1,
);
self.add(
ArcOpcode::OR,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
4,
1,
);
self.add(
ArcOpcode::XOR,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
4,
1,
);
self.add(
ArcOpcode::BIC,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
4,
1,
);
self.add(
ArcOpcode::BIC1,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
4,
1,
);
self.add(
ArcOpcode::ASL,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
4,
1,
);
self.add(
ArcOpcode::ASL1,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
4,
1,
);
self.add(
ArcOpcode::ASR,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
4,
1,
);
self.add(
ArcOpcode::ASR1,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
4,
1,
);
self.add(
ArcOpcode::LSR,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
4,
1,
);
self.add(
ArcOpcode::LSR1,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
4,
1,
);
self.add(
ArcOpcode::ROR,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
4,
1,
);
self.add(
ArcOpcode::MOV,
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
false,
4,
1,
);
self.add(
ArcOpcode::MOV_S,
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
false,
2,
1,
);
self.add(
ArcOpcode::MOVHI,
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
false,
4,
1,
);
self.add(
ArcOpcode::CMP,
false,
false,
false,
false,
true,
false,
false,
false,
true,
false,
false,
4,
1,
);
self.add(
ArcOpcode::RCMP,
false,
false,
false,
false,
true,
false,
false,
false,
true,
false,
false,
4,
1,
);
self.add(
ArcOpcode::LD,
false,
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::LD_S,
false,
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
2,
2,
);
self.add(
ArcOpcode::LDB,
false,
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::LDB_S,
false,
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
2,
2,
);
self.add(
ArcOpcode::LDW,
false,
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::LDW_S,
false,
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
2,
2,
);
self.add(
ArcOpcode::ST,
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::ST_S,
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
false,
2,
2,
);
self.add(
ArcOpcode::STB,
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::STB_S,
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
false,
2,
2,
);
self.add(
ArcOpcode::STW,
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::STW_S,
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
false,
2,
2,
);
self.add(
ArcOpcode::B,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::B_S,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
2,
2,
);
self.add(
ArcOpcode::BL,
true,
true,
true,
false,
false,
false,
false,
false,
true,
false,
false,
4,
2,
);
self.add(
ArcOpcode::BL_S,
true,
true,
true,
false,
false,
false,
false,
false,
true,
false,
false,
2,
2,
);
self.add(
ArcOpcode::J,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::J_S,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
2,
2,
);
self.add(
ArcOpcode::JL,
true,
true,
true,
false,
false,
false,
false,
false,
true,
false,
false,
4,
2,
);
self.add(
ArcOpcode::JL_S,
true,
true,
true,
false,
false,
false,
false,
false,
true,
false,
false,
2,
2,
);
self.add(
ArcOpcode::BR,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::BNE,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::BEQ,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::BGT,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::BGE,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::BLT,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::BLE,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::BHI,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::BHS,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::BLO,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::BLS,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::LP,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
4,
1,
);
self.add(
ArcOpcode::FLAG,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
4,
1,
);
self.add(
ArcOpcode::SEXB,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
1,
);
self.add(
ArcOpcode::SEXW,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
1,
);
self.add(
ArcOpcode::EXTB,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
1,
);
self.add(
ArcOpcode::EXTW,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
1,
);
self.add(
ArcOpcode::ABS,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
1,
);
self.add(
ArcOpcode::NEG,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
1,
);
self.add(
ArcOpcode::MAX,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
4,
1,
);
self.add(
ArcOpcode::MIN,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
4,
1,
);
self.add(
ArcOpcode::SWAP,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
1,
);
self.add(
ArcOpcode::NORM,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
1,
);
self.add(
ArcOpcode::NORMH,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
1,
);
self.add(
ArcOpcode::SAT16,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
1,
);
self.add(
ArcOpcode::ADDS,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
true,
4,
1,
);
self.add(
ArcOpcode::SUBS,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
true,
4,
1,
);
self.add(
ArcOpcode::MUL64,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
4,
4,
);
self.add(
ArcOpcode::MULU64,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
4,
4,
);
self.add(
ArcOpcode::DIV,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
32,
);
self.add(
ArcOpcode::BARREL_SHIFTER,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
2,
);
self.add(
ArcOpcode::BMSK,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
1,
);
self.add(
ArcOpcode::BMSKN,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
1,
);
self.add(
ArcOpcode::NOP,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
1,
);
self.add(
ArcOpcode::BRK,
true,
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
4,
1,
);
self.add(
ArcOpcode::SLEEP,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
4,
1,
);
self.add(
ArcOpcode::SWI,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
4,
1,
);
self.add(
ArcOpcode::RTIE,
true,
false,
false,
true,
false,
false,
false,
false,
true,
false,
false,
4,
1,
);
}
}
impl Default for ArcInstrInfo {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_all_opcodes_registered() {
let info = ArcInstrInfo::new();
assert!(info.get_desc(ArcOpcode::ADD).is_some());
assert!(info.get_desc(ArcOpcode::LD).is_some());
assert!(info.get_desc(ArcOpcode::B).is_some());
assert!(info.get_desc(ArcOpcode::NOP).is_some());
}
#[test]
fn test_terminators() {
let info = ArcInstrInfo::new();
assert!(info.is_terminator(ArcOpcode::B));
assert!(info.is_terminator(ArcOpcode::BL));
assert!(info.is_terminator(ArcOpcode::J));
assert!(info.is_terminator(ArcOpcode::BR));
assert!(info.is_terminator(ArcOpcode::RTIE));
assert!(!info.is_terminator(ArcOpcode::ADD));
}
#[test]
fn test_branches() {
let info = ArcInstrInfo::new();
assert!(info.is_branch(ArcOpcode::B));
assert!(info.is_branch(ArcOpcode::BNE));
assert!(info.is_branch(ArcOpcode::BEQ));
assert!(info.is_branch(ArcOpcode::BGT));
assert!(!info.is_branch(ArcOpcode::MOV));
assert!(!info.is_branch(ArcOpcode::RTIE));
}
#[test]
fn test_calls() {
let info = ArcInstrInfo::new();
assert!(info.is_call(ArcOpcode::BL));
assert!(info.is_call(ArcOpcode::JL));
assert!(!info.is_call(ArcOpcode::B));
assert!(!info.is_call(ArcOpcode::BR));
}
#[test]
fn test_loads_stores() {
let info = ArcInstrInfo::new();
assert!(info.may_load(ArcOpcode::LD));
assert!(info.may_load(ArcOpcode::LDB));
assert!(info.may_load(ArcOpcode::LDW));
assert!(!info.may_load(ArcOpcode::ST));
assert!(info.may_store(ArcOpcode::ST));
assert!(info.may_store(ArcOpcode::STB));
assert!(!info.may_store(ArcOpcode::LD));
}
#[test]
fn test_instruction_sizes() {
let info = ArcInstrInfo::new();
let desc = info.get_desc(ArcOpcode::ADD).unwrap();
assert_eq!(desc.size_bytes, 4);
let desc_s = info.get_desc(ArcOpcode::MOV_S).unwrap();
assert_eq!(desc_s.size_bytes, 2);
}
#[test]
fn test_arithmetic_mnemonics() {
assert_eq!(ArcOpcode::ADD.mnemonic(), "add");
assert_eq!(ArcOpcode::SUB.mnemonic(), "sub");
assert_eq!(ArcOpcode::AND.mnemonic(), "and");
assert_eq!(ArcOpcode::OR.mnemonic(), "or");
assert_eq!(ArcOpcode::XOR.mnemonic(), "xor");
}
#[test]
fn test_branch_mnemonics() {
assert_eq!(ArcOpcode::B.mnemonic(), "b");
assert_eq!(ArcOpcode::BNE.mnemonic(), "bne");
assert_eq!(ArcOpcode::BEQ.mnemonic(), "beq");
assert_eq!(ArcOpcode::BGT.mnemonic(), "bgt");
assert_eq!(ArcOpcode::BLT.mnemonic(), "blt");
assert_eq!(ArcOpcode::BLS.mnemonic(), "bls");
}
#[test]
fn test_compare_ops() {
let info = ArcInstrInfo::new();
let desc = info.get_desc(ArcOpcode::CMP).unwrap();
assert!(desc.is_compare);
assert!(!info.is_terminator(ArcOpcode::CMP));
}
#[test]
fn test_default() {
let info = ArcInstrInfo::default();
assert!(info.get_desc(ArcOpcode::ADD).is_some());
}
}