use regs::{GeneralPurposeRegister, GeneralPurposeRegisterPair, IORegister, StatusFlag, PC}; use std::fmt; #[derive(Debug)] pub enum DecodingError { UndefinedInstruction(u16), TruncatedInstruction, } #[derive(Debug)] pub enum IncrementMode { None, // [Z] PreDecrement, // [-Z] PostIncrement, // [Z+] ConstantOffset(u8), // e.g. [Z+q] } #[derive(Debug)] #[allow(non_camel_case_types)] pub enum Instruction { ADC(GeneralPurposeRegister, GeneralPurposeRegister), ADD(GeneralPurposeRegister, GeneralPurposeRegister), ADIW(GeneralPurposeRegisterPair, u16), AND(GeneralPurposeRegister, GeneralPurposeRegister), ANDI(GeneralPurposeRegister, u8), ASR(GeneralPurposeRegister), BLD(GeneralPurposeRegister, u8), BREAK, BR_IF(i8, StatusFlag, bool), BST(GeneralPurposeRegister, u8), CALL(PC), CBI(IORegister, u8), CLR_FLAG(StatusFlag), CLR(GeneralPurposeRegister), // TODO: Find CLR flag thingy COM(GeneralPurposeRegister), CP(GeneralPurposeRegister, GeneralPurposeRegister), CPC(GeneralPurposeRegister, GeneralPurposeRegister), CPI(GeneralPurposeRegister, u8), CPSE(GeneralPurposeRegister, GeneralPurposeRegister), DEC(GeneralPurposeRegister), EICALL, EIJMP, ELPM(GeneralPurposeRegister, IncrementMode), // Only supports PostIncrement EOR(GeneralPurposeRegister, GeneralPurposeRegister), FMUL(GeneralPurposeRegister, GeneralPurposeRegister), FMULS(GeneralPurposeRegister, GeneralPurposeRegister), FMULSU(GeneralPurposeRegister, GeneralPurposeRegister), ICALL, IJMP, IN(GeneralPurposeRegister, IORegister), INC(GeneralPurposeRegister), JMP(PC), LAC(GeneralPurposeRegister), LAS(GeneralPurposeRegister), LAT(GeneralPurposeRegister), LD( GeneralPurposeRegister, GeneralPurposeRegisterPair, IncrementMode, ), LDI(GeneralPurposeRegister, u8), LDS8(GeneralPurposeRegister, u8), // Two variants, with u8 and u16 LDS16(GeneralPurposeRegister, u16), LPM(GeneralPurposeRegister, IncrementMode), // Only supports PostIncrement LSL(GeneralPurposeRegister), LSR(GeneralPurposeRegister), MOV(GeneralPurposeRegister, GeneralPurposeRegister), MOVW(GeneralPurposeRegisterPair, GeneralPurposeRegisterPair), MUL(GeneralPurposeRegister, GeneralPurposeRegister), MULS(GeneralPurposeRegister, GeneralPurposeRegister), MULSU(GeneralPurposeRegister, GeneralPurposeRegister), NEG(GeneralPurposeRegister), NOP, OR(GeneralPurposeRegister, GeneralPurposeRegister), ORI(GeneralPurposeRegister, u8), OUT(IORegister, GeneralPurposeRegister), POP(GeneralPurposeRegister), PUSH(GeneralPurposeRegister), RCALL(i16), // These are relative and have only 12 bits. RET, RETI, RJMP(i16), // These are relative and have only 12 bits. ROL(GeneralPurposeRegister), ROR(GeneralPurposeRegister), SBC(GeneralPurposeRegister, GeneralPurposeRegister), SBCI(GeneralPurposeRegister, u8), SBI(IORegister, u8), SBIC(IORegister, u8), SBIS(IORegister, u8), SBIW(GeneralPurposeRegisterPair, u16), // SBR(GeneralPurposeRegister, u8), => is the same as ORI, so ignore this :) SBRC(GeneralPurposeRegister, u8), SBRS(GeneralPurposeRegister, u8), SER(GeneralPurposeRegister), SET_FLAG(StatusFlag), // TODO how is it really called? (CLR) SLEEP, SPM(IncrementMode), // Only supports PostIncrement ST( GeneralPurposeRegisterPair, GeneralPurposeRegister, IncrementMode, ), STS8(u8, GeneralPurposeRegister), // Two variants, u8/u16 STS16(u16, GeneralPurposeRegister), SUB(GeneralPurposeRegister, GeneralPurposeRegister), SUBI(GeneralPurposeRegister, u8), SWAP(GeneralPurposeRegister), TST(GeneralPurposeRegister), WDR, XCH(GeneralPurposeRegister), } impl fmt::Display for Instruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Instruction::ADC(ref r, ref d) => write!(f, "ADC {}, {}", r, d), Instruction::ADD(ref r, ref d) => write!(f, "ADD {}, {}", r, d), Instruction::ADIW(ref r, v) => write!(f, "ADIW {}, {}", r, v), Instruction::AND(ref r, ref d) => write!(f, "AND {}, {}", r, d), Instruction::ANDI(ref r, v) => write!(f, "ANDI {}, {}", r, v), Instruction::ASR(ref r) => write!(f, "ASR {}", r), Instruction::BLD(ref r, v) => write!(f, "BLD {}, {}", r, v), Instruction::BREAK => write!(f, "BREAK"), Instruction::BR_IF(rel, ref flag, tgt) => { write!(f, "BR_IF {}, {:?}=={}", rel, flag, tgt) } Instruction::BST(ref r, v) => write!(f, "BST {}, {}", r, v), Instruction::CALL(pc) => write!(f, "CALL {:06X}", pc), Instruction::CBI(ref ior, v) => write!(f, "CBI {}, {}", ior, v), Instruction::CLR_FLAG(flag) => write!(f, "CLR_FLAG {:?}", flag), Instruction::CLR(ref r) => write!(f, "CLR {}", r), Instruction::COM(ref r) => write!(f, "COM {}", r), Instruction::CP(ref r, ref d) => write!(f, "CP {}, {}", r, d), Instruction::CPC(ref r, ref d) => write!(f, "CPC {}, {}", r, d), Instruction::CPI(ref r, v) => write!(f, "CPI {} {}", r, v), Instruction::CPSE(ref r, ref d) => write!(f, "CPSE {} {}", r, d), Instruction::DEC(ref r) => write!(f, "DEC {}", r), Instruction::EICALL => write!(f, "EICALL"), Instruction::EIJMP => write!(f, "EIJMP"), Instruction::ELPM(ref r, ref mode) => write!(f, "ELPM[{:?}] {}", mode, r), Instruction::EOR(ref r, ref d) => write!(f, "EOR {}, {}", r, d), Instruction::FMUL(ref r, ref d) => write!(f, "FMUL {}, {}", r, d), Instruction::FMULS(ref r, ref d) => write!(f, "FMULS {}, {}", r, d), Instruction::FMULSU(ref r, ref d) => write!(f, "FMULSU {}, {}", r, d), Instruction::ICALL => write!(f, "ICALL"), Instruction::IJMP => write!(f, "IJMP"), Instruction::IN(ref r, ref ior) => write!(f, "IN {}, {}", r, ior), Instruction::INC(ref r) => write!(f, "INC {}", r), Instruction::JMP(pc) => write!(f, "JMP {:06X}", pc), Instruction::LAC(ref r) => write!(f, "LAC {}", r), Instruction::LAS(ref r) => write!(f, "LAS {}", r), Instruction::LAT(ref r) => write!(f, "LAT {}", r), Instruction::LD(ref r, ref d, ref mode) => write!(f, "LD {}, [{} {:?}]", r, d, mode), Instruction::LDI(ref r, v) => write!(f, "LDI {}, {}", r, v), Instruction::LDS8(ref r, v) => write!(f, "LDS8 {}, {}", r, v), Instruction::LDS16(ref r, v) => write!(f, "LDS16 {}, {}", r, v), Instruction::LPM(ref r, ref mode) => write!(f, "LPM {} {:?}", r, mode), Instruction::LSL(ref r) => write!(f, "LSL {}", r), Instruction::LSR(ref r) => write!(f, "LSR {}", r), Instruction::MOV(ref r, ref d) => write!(f, "MOV {}, {}", r, d), Instruction::MOVW(ref r, ref d) => write!(f, "MOVW {}, {}", r, d), Instruction::MUL(ref r, ref d) => write!(f, "MUL {}, {}", r, d), Instruction::MULS(ref r, ref d) => write!(f, "MULS {}, {}", r, d), Instruction::MULSU(ref r, ref d) => write!(f, "MULSU {}, {}", r, d), Instruction::NEG(ref r) => write!(f, "NEG {}", r), Instruction::NOP => write!(f, "NOP"), Instruction::OR(ref r, ref d) => write!(f, "OR {} {}", r, d), Instruction::ORI(ref r, v) => write!(f, "ORI {} {}", r, v), Instruction::OUT(ref ior, ref d) => write!(f, "OUT {}, {}", ior, d), Instruction::POP(ref r) => write!(f, "POP {}", r), Instruction::PUSH(ref r) => write!(f, "PUSH {}", r), Instruction::RCALL(rv) => write!(f, "RCALL {:X}", rv), Instruction::RET => write!(f, "RET"), Instruction::RETI => write!(f, "RETI"), Instruction::RJMP(rv) => write!(f, "RJMP {:X}", rv), Instruction::ROL(ref r) => write!(f, "ROL {}", r), Instruction::ROR(ref r) => write!(f, "ROR {}", r), Instruction::SBC(ref r, ref d) => write!(f, "SBC {}, {}", r, d), Instruction::SBCI(ref r, v) => write!(f, "SBCI {}, {}", r, v), Instruction::SBI(ref ior, v) => write!(f, "SBI {}, {}", ior, v), Instruction::SBIC(ref ior, v) => write!(f, "SBIC {}, {}", ior, v), Instruction::SBIS(ref ior, v) => write!(f, "SBIS {}, {}", ior, v), Instruction::SBIW(ref r, v) => write!(f, "SBIW {}, {}", r, v), Instruction::SBRC(ref r, v) => write!(f, "SBRC {}, {}", r, v), Instruction::SBRS(ref r, v) => write!(f, "SBRS {}, {}", r, v), Instruction::SER(ref r) => write!(f, "SER {}", r), Instruction::SET_FLAG(flag) => write!(f, "SET_FLAG {:?}", flag), Instruction::SLEEP => write!(f, "SLEEP"), Instruction::SPM(ref mode) => write!(f, "SPM {:?}", mode), Instruction::ST(ref r, ref d, ref mode) => write!(f, "ST [{} {:?}], {}", r, mode, d), Instruction::STS8(v, ref r) => write!(f, "STS8 {}, {}", v, r), Instruction::STS16(v, ref r) => write!(f, "STS16 {}, {}", v, r), Instruction::SUB(ref r, ref d) => write!(f, "SUB {}, {}", r, d), Instruction::SUBI(ref r, v) => write!(f, "SUBI {}, {}", r, v), Instruction::SWAP(ref r) => write!(f, "SWAP {}", r), Instruction::TST(ref r) => write!(f, "TST {}", r), Instruction::WDR => write!(f, "WDR"), Instruction::XCH(ref r) => write!(f, "XCH {}", r), } } } impl Instruction { // TODO: There are more // LDS32 STS32 pub fn size(&self) -> usize { match *self { Instruction::JMP(_) | Instruction::CALL(_) | Instruction::STS16(_, _) | Instruction::LDS16(_, _) => 4, _ => 2, } } pub fn cycles(&self) -> usize { // TODO: Implement this correctly. 2 } } pub fn decode(data: &[u8]) -> Result { if data.len() < 2 { return Err(DecodingError::TruncatedInstruction); } // Try to match 2b instructions without any parameters first. let v: u16 = (u16::from(data[1]) << 8) | u16::from(data[0]); // Load second u16 as well if possible let v2: Option = if data.len() >= 4 { Some((u16::from(data[3]) << 8) | u16::from(data[2])) } else { None }; // Status reg operations (set and clear bits). match v & 0b1111_1111_1000_1111 { 0b1001_0100_1000_1000 => { // CLR_FLAG TODO HOW IS IT CALLED let idx = ((v & 0b0000_0000_0111_0000) >> 4) as u8; return Ok(Instruction::CLR_FLAG( StatusFlag::try_from_idx(idx).unwrap(), )); } 0b1001_0100_0000_1000 => { // SET_FLAG TODO HOW IS IT CALLED let idx = ((v & 0b0000_0000_0111_0000) >> 4) as u8; return Ok(Instruction::SET_FLAG( StatusFlag::try_from_idx(idx).unwrap(), )); } _ => {} } // Other instructions with no parameters. match v { 0b1001_0101_1001_1000 => return Ok(Instruction::BREAK), 0b1001_0101_0001_1001 => return Ok(Instruction::EICALL), 0b1001_0100_0001_1001 => return Ok(Instruction::EIJMP), 0b1001_0101_1101_1000 => return Ok(Instruction::ELPM(0.into(), IncrementMode::None)), 0b1001_0101_0000_1001 => return Ok(Instruction::ICALL), 0b1001_0100_0000_1001 => return Ok(Instruction::IJMP), 0b1001_0101_1100_1000 => return Ok(Instruction::LPM(0.into(), IncrementMode::None)), 0b0000_0000_0000_0000 => return Ok(Instruction::NOP), 0b1001_0101_0000_1000 => return Ok(Instruction::RET), 0b1001_0101_0001_1000 => return Ok(Instruction::RETI), 0b1001_0101_1000_1000 => return Ok(Instruction::SLEEP), 0b1001_0101_1110_1000 => return Ok(Instruction::SPM(IncrementMode::None)), 0b1001_0101_1111_1000 => return Ok(Instruction::SPM(IncrementMode::PostIncrement)), 0b1001_0101_1010_1000 => return Ok(Instruction::WDR), _ => {} } // Now things will get ugly, we have a lot of different prefix sizes for // different instructions. /* 0000_0011_1: 0000_0011_0: */ if v & 0b1111_1111_0000_0000 == 0b0000_0011_0000_0000 { // FMUL/FMULS/FMULSU/MULSU let d = ((v & 0b0111_0000) >> 4) as u8; let r = ((v & 0b0111)) as u8; let mode = v & 0b1000_1000; match mode { 0b0000_0000 => return Ok(Instruction::MULSU((d + 16).into(), (r + 16).into())), 0b0000_1000 => return Ok(Instruction::FMUL((d + 16).into(), (r + 16).into())), 0b1000_0000 => return Ok(Instruction::FMULS((d + 16).into(), (r + 16).into())), 0b1000_1000 => return Ok(Instruction::FMULSU((d + 16).into(), (r + 16).into())), _ => unreachable!(), } } /* 10010110: '1001 0110 KKdd KKKK' 00000001: '0000 0001 dddd rrrr' 00000010: '0000 0010 dddd rrrr' 10010111: '1001 0111 KKdd KKKK' 11101111: '1110 1111 dddd 1111' 10011010: '1001 1010 AAAA Abbb' 10011011: '1001 1011 AAAA Abbb' 10011001: '1001 1001 AAAA Abbb' 10011000: '1001 1000 AAAA Abbb' */ { let K = (((v & 0b1100_0000) >> 2) | (v & 0b1111)) as u8; let d = ((v & 0b1111_0000) >> 4) as u8; let r = (v & 0b1111) as u8; let A = u16::from((v & 0b1111_1000) >> 3); let b = (v & 0b0111) as u8; match v & 0b1111_1111_0000_0000 { 0b1001_0110_0000_0000 => { return Ok(Instruction::ADIW(((d & 0b11) * 2 + 24).into(), u16::from(K))) } 0b0000_0001_0000_0000 => return Ok(Instruction::MOVW((d * 2).into(), (r * 2).into())), 0b0000_0010_0000_0000 => return Ok(Instruction::MULS((d + 16).into(), (r + 16).into())), 0b1001_0111_0000_0000 => { return Ok(Instruction::SBIW(((d & 0b11) * 2 + 24).into(), u16::from(K))) } 0b1110_1111_0000_0000 => if r == 0b1111 { return Ok(Instruction::SER((d + 16).into())); }, 0b1001_1010_0000_0000 => return Ok(Instruction::SBI(A, b)), 0b1001_1011_0000_0000 => return Ok(Instruction::SBIS(A, b)), 0b1001_1001_0000_0000 => return Ok(Instruction::SBIC(A, b)), 0b1001_1000_0000_0000 => return Ok(Instruction::CBI(A, b)), _ => {} } } /* 1001001: 1001000: */ // Handle LD{X,Y,Z}'s (none, incre and decre, just no offset) { if v & 0b1110_1100_0000_0000 == 0b1000_0000_0000_0000 { let dr = (((v & 0b1_1111_0000) >> 4) as u8).into(); // mode: 00 -> None, 01 -> PostIncrement, 10 -> PreDecrement let mode = v & 0b11; let do_store = v & 0b0010_0000_0000 != 0; match ( do_store, v & 0b0001_0000_0000_0000 > 0, (v >> 2) & 0b11, mode, ) { // LD X (false, true, 0b11, 0b00) => { return Ok(Instruction::LD(dr, 26.into(), IncrementMode::None)) } (false, true, 0b11, 0b01) => { return Ok(Instruction::LD(dr, 26.into(), IncrementMode::PostIncrement)) } (false, true, 0b11, 0b10) => { return Ok(Instruction::LD(dr, 26.into(), IncrementMode::PreDecrement)) } // LD Y (false, false, 0b10, 0b00) => { return Ok(Instruction::LD(dr, 28.into(), IncrementMode::None)) } (false, true, 0b10, 0b01) => { return Ok(Instruction::LD(dr, 28.into(), IncrementMode::PostIncrement)) } (false, true, 0b10, 0b10) => { return Ok(Instruction::LD(dr, 28.into(), IncrementMode::PreDecrement)) } // LD Z (false, false, 0b00, 0b00) => { return Ok(Instruction::LD(dr, 30.into(), IncrementMode::None)) } (false, true, 0b00, 0b01) => { return Ok(Instruction::LD(dr, 30.into(), IncrementMode::PostIncrement)) } (false, true, 0b00, 0b10) => { return Ok(Instruction::LD(dr, 30.into(), IncrementMode::PreDecrement)) } // ST X (true, true, 0b11, 0b00) => { return Ok(Instruction::ST(26.into(), dr, IncrementMode::None)) } (true, true, 0b11, 0b01) => { return Ok(Instruction::ST(26.into(), dr, IncrementMode::PostIncrement)) } (true, true, 0b11, 0b10) => { return Ok(Instruction::ST(26.into(), dr, IncrementMode::PreDecrement)) } // ST Y (true, false, 0b10, 0b00) => { return Ok(Instruction::ST(28.into(), dr, IncrementMode::None)) } (true, true, 0b10, 0b01) => { return Ok(Instruction::ST(28.into(), dr, IncrementMode::PostIncrement)) } (true, true, 0b10, 0b10) => { return Ok(Instruction::ST(28.into(), dr, IncrementMode::PreDecrement)) } // ST Z (true, false, 0b00, 0b00) => { return Ok(Instruction::ST(30.into(), dr, IncrementMode::None)) } (true, true, 0b00, 0b01) => { return Ok(Instruction::ST(30.into(), dr, IncrementMode::PostIncrement)) } (true, true, 0b00, 0b10) => { return Ok(Instruction::ST(30.into(), dr, IncrementMode::PreDecrement)) } // POP: 1001 000d dddd 1111 (false, true, 0b11, 0b11) => return Ok(Instruction::POP(dr)), // PUSH: 1001 001d dddd 1111 (true, true, 0b11, 0b11) => return Ok(Instruction::PUSH(dr)), // LAC: 1001 001r rrrr 0110 (true, true, 0b01, 0b10) => return Ok(Instruction::LAC(dr)), // LAS: 1001 001r rrrr 0101 (true, true, 0b01, 0b01) => return Ok(Instruction::LAS(dr)), // LAT: 1001 001r rrrr 0111 (true, true, 0b01, 0b11) => return Ok(Instruction::LAT(dr)), // XCH: 1001 001r rrrr 0100 (true, true, 0b01, 0b00) => return Ok(Instruction::XCH(dr)), // ELPM (2) 1001 000d dddd 0110 (false, true, 0b01, 0b10) => return Ok(Instruction::ELPM(dr, IncrementMode::None)), // ELPM (3) 1001 000d dddd 0111 (false, true, 0b01, 0b11) => { return Ok(Instruction::ELPM(dr, IncrementMode::PostIncrement)) } // LPM (2): 1001 000d dddd 0100 (false, true, 0b01, 0b00) => return Ok(Instruction::LPM(dr, IncrementMode::None)), // LPM (3): 1001 000d dddd 0101 (false, true, 0b01, 0b01) => { return Ok(Instruction::LPM(dr, IncrementMode::PostIncrement)) } // TODO: LDS32 STS32 // STS32 1001 001r rrrr 0000 kkkk kkkk kkkk kkkk (true, true, 0, 0) => { //STS32 match v2 { Some(k) => return Ok(Instruction::STS16(k, dr)), None => return Err(DecodingError::TruncatedInstruction), } } // LDS32 1001 000d dddd 0000 kkkk kkkk kkkk kkkk (false, true, 0, 0) => { //LDS32 match v2 { Some(k) => return Ok(Instruction::LDS16(dr, k)), None => return Err(DecodingError::TruncatedInstruction), } } _ => {} } } } //LDX1 1001 000d dddd 1100 //LDX2 1001 000d dddd 1101 //LDX3 1001 000d dddd 1110 //LDY1 1000 000d dddd 1000 //LDY2 1001 000d dddd 1001 //LDY3 1001 000d dddd 1010 //LDZ1 1000 000d dddd 0000 //LDZ2 1001 000d dddd 0001 //LDZ3 1001 000d dddd 0010 //STY1 1000 001r rrrr 1000 //STY2 1001 001r rrrr 1001 //STY3 1001 001r rrrr 1010 match v & 0b1111_1110_0000_0000 { 0b1111_1100_0000_0000 | 0b1111_1110_0000_0000 => { // 1111110: // 1111111: // 1111 110r rrrr 0bbb let r = (((v >> 4) & 0b1_1111) as u8).into(); let b = (v & 0b111) as u8; if (v & 0b1000) == 0 { if ((v >> 9) & 1) == 0 { return Ok(Instruction::SBRC(r, b)); } else { return Ok(Instruction::SBRS(r, b)); } } } // BLD '1111 100d dddd 0bbb' // BST '1111 101d dddd 0bbb' 0b1111_1000_0000_0000 | 0b1111_1010_0000_0000 => { let d = (((v >> 4) & 0b1_1111) as u8).into(); let b = (v & 0b111) as u8; if (v & 0b1000) == 0 { if ((v >> 9) & 1) == 1 { return Ok(Instruction::BLD(d, b)); } else { return Ok(Instruction::BST(d, b)); } } } 0b1001_0100_0000_0000 => { /* 1001010: */ let d = (((v & 0b0000_0001_1111_0000) >> 4) as u8).into(); // ASR '1001 010d dddd 0101 // COM '1001 010d dddd 0000' // DEC '1001 010d dddd 1010' // INC '1001 010d dddd 0011' // LSR '1001 010d dddd 0110' // NEG '1001 010d dddd 0001' // ROR '1001 010d dddd 0111' // SWP '1001 010d dddd 0010' match v & 0b1111 { 0b0101 => return Ok(Instruction::ASR(d)), 0b0000 => return Ok(Instruction::COM(d)), 0b1010 => return Ok(Instruction::DEC(d)), 0b0011 => return Ok(Instruction::INC(d)), 0b0110 => return Ok(Instruction::LSR(d)), 0b0001 => return Ok(Instruction::NEG(d)), 0b0111 => return Ok(Instruction::ROR(d)), 0b0010 => return Ok(Instruction::SWAP(d)), // CALL 1001 010k kkkk 111k kkkk kkkk kkkk kkkk' // JMP '1001 010k kkkk 110k kkkk kkkk kkkk kkkk' 0b1100 | 0b1101 | 0b1110 | 0b1111 => { // u32 instruction match v2 { None => return Err(DecodingError::TruncatedInstruction), Some(kl) => { let k = (u32::from(v & 0b1111_0000) << 12) | (u32::from(kl)); if v & 0b10 == 0 { return Ok(Instruction::JMP(k)); } else { return Ok(Instruction::CALL(k)); } } } } _ => {} } } _ => {} } { let d5 = (((v >> 4) & 0b1_1111) as u8).into(); let r5 = (((v & 0b1111) | ((v >> 5) & 0b1_0000)) as u8).into(); match v & 0b1111_1100_0000_0000 { 0b0001_1000_0000_0000 => return Ok(Instruction::SUB(d5, r5)), 0b0001_1100_0000_0000 => { if d5 == r5 { return Ok(Instruction::ROL(d5)); } else { return Ok(Instruction::ADC(d5, r5)); } } 0b0000_1100_0000_0000 => { if d5 == r5 { return Ok(Instruction::LSL(d5)); } else { return Ok(Instruction::ADD(d5, r5)); } } 0b0000_1000_0000_0000 => return Ok(Instruction::SBC(d5, r5)), 0b0000_0100_0000_0000 => return Ok(Instruction::CPC(d5, r5)), 0b1001_1100_0000_0000 => return Ok(Instruction::MUL(d5, r5)), 0b0001_0100_0000_0000 => return Ok(Instruction::CP(d5, r5)), 0b0001_0000_0000_0000 => return Ok(Instruction::CPSE(d5, r5)), 0b0010_0100_0000_0000 => { if d5 == r5 { return Ok(Instruction::CLR(d5)); } else { return Ok(Instruction::EOR(d5, r5)); } } 0b0010_0000_0000_0000 => { if d5 == r5 { return Ok(Instruction::TST(d5)); } else { return Ok(Instruction::AND(d5, r5)); } } 0b0010_1000_0000_0000 => return Ok(Instruction::OR(d5, r5)), 0b0010_1100_0000_0000 => return Ok(Instruction::MOV(d5, r5)), // Branch instructions // 0b1111_0000_0000_0000 => // 0b1111_0100_0000_0000 => 0b1111_0100_0000_0000 | 0b1111_0000_0000_0000 => { let flag_should_be_set = ((v >> 10) & 1) == 0; let flag = StatusFlag::try_from_idx((v & 0b111) as u8).unwrap(); let mut k = ((v >> 3) & 0b0111_1111) as i8; if k >= (1 << 6) { k = k.wrapping_sub(1 << 7); } return Ok(Instruction::BR_IF(k, flag, flag_should_be_set)); } _ => {} } } { // OUT 1011 1AAr rrrr AAAA // IN '1011 0AAd dddd AAAA let r = (((v >> 4) & 0b1_1111) as u8).into(); let A = ((((v >> 5) & 0b11_0000) | (v & 0b1111)) as u8).into(); // STS return '1010 1kkk rrrr kkkk'.replace(' ', '') // LDS return '1010 0kkk dddd kkkk'.replace(' ', '') // 1010 0kkk dddd kkkk // ST_ return "10q0 qq1r rrrr 0qqq".replace(' ', '') // 10q0 qq1r rrrr 0qqq let r16 = (((v >> 4) & 0b1111) as u8).into(); let k = (((v >> 4) & 0b111_0000) | (v & 0b1111)) as u8; match v & 0b1111_1000_0000_0000 { 0b1011_1000_0000_0000 => return Ok(Instruction::OUT(A, r)), 0b1011_0000_0000_0000 => return Ok(Instruction::IN(r, A)), 0b1010_1000_0000_0001 => return Ok(Instruction::STS8(k + 0x40, r16)), // Disabled, can't be used 0b1010_0000_0000_0001 => return Ok(Instruction::LDS8(r16, k + 0x40)), // Disabled, can't be used _ => {} } } { // Rcall/jmp: 1101 kkkk kkkk kkkk // SBR 0110 KKKK dddd KKKK // ORI: 0110 KKKK dddd KKKK // ANDI 0111 KKKK dddd KKKK // CPI 0011 KKKK dddd KKKK // SUBI 0101 KKKK dddd KKKK // SBCI 0100 KKKK dddd KKKK // LDI 1110 KKKK dddd KKKK // 0110: // 0111: // 0011: // 0101: // 0100: // 1110: // 1100: // 1101: let k = (v & 0b0000_1111_1111_1111) as i16; let k: i16 = if (k & 0b1000_0000_0000) == 0b1000_0000_0000 { k - 0b1_0000_0000_0000 } else { k }; let K = (((v >> 4) & 0b1111_0000) | (v & 0b1111)) as u8; let d = (((v >> 4) & 0b1111) as u8 + 16u8).into(); match v & 0b1111_0000_0000_0000 { 0b0110_0000_0000_0000 => return Ok(Instruction::ORI(d, K)), 0b0111_0000_0000_0000 => return Ok(Instruction::ANDI(d, K)), 0b0011_0000_0000_0000 => return Ok(Instruction::CPI(d, K)), 0b0101_0000_0000_0000 => return Ok(Instruction::SUBI(d, K)), 0b0100_0000_0000_0000 => return Ok(Instruction::SBCI(d, K)), 0b1110_0000_0000_0000 => return Ok(Instruction::LDI(d, K)), 0b1100_0000_0000_0000 => return Ok(Instruction::RJMP(k)), 0b1101_0000_0000_0000 => return Ok(Instruction::RCALL(k)), _ => {} } } // return '10q0 qq0d dddd 1qqq'.replace(' ', '') LD Y IV // return '10q0 qq0d dddd 0qqq'.replace(' ', '') LD Z IV // return "10q0 qq1r rrrr 1qqq".replace(' ', '') ST Y IV // return "10q0 qq1r rrrr 0qqq".replace(' ', '') ST Z IV if (v >> 12) & 0b1101 == 0b1000 { let w = ((v >> 9) & 1) == 1; let dr = (((v >> 4) & 0b11111) as u8).into(); let q = (((v >> 8) & 0b10_0000) | ((v >> 7) & 0b1_1000) | (v & 0b111)) as u8; match (v & 0b1000, w) { (0b1000, false) => { return Ok(Instruction::LD( dr, 28.into(), IncrementMode::ConstantOffset(q), )) } (0b1000, true) => { return Ok(Instruction::ST( 28.into(), dr, IncrementMode::ConstantOffset(q), )) } (0b0000, false) => { return Ok(Instruction::LD( dr, 30.into(), IncrementMode::ConstantOffset(q), )) } (0b0000, true) => { return Ok(Instruction::ST( 30.into(), dr, IncrementMode::ConstantOffset(q), )) } _ => {} } } Err(DecodingError::UndefinedInstruction(v)) }