use super::config::*;
use super::instruction::*;
use super::operand::*;
use crate::error::Result;
use std::collections::HashSet;
pub(crate) mod decoder;
#[derive(Clone, Debug)]
pub struct Decoder<'a> {
pub(crate) data: &'a [u8],
pub(crate) config: Config,
pub(crate) it_block: Option<ItBlock>,
pub(crate) block_decoding: bool,
pub(crate) pc: u32,
pub(crate) labels: HashSet<u32>,
}
impl<'a> Decoder<'a> {
pub fn new(data: &'a [u8], config: Config) -> Self {
Self {
data,
it_block: None,
config,
block_decoding: false,
pc: 0,
labels: HashSet::new(),
}
}
pub fn decode(&mut self) -> Result<Instruction> {
let mut instruction = decoder::decode(self)?;
self.check_condition(&mut instruction)?;
instruction.pc = self.pc;
self.pc += instruction.size as u32;
Ok(instruction)
}
pub fn decode_block(&mut self, pc: u32) -> Result<InstructionBlock> {
self.pc = pc;
self.labels.clear();
self.block_decoding = true;
let mut block = InstructionBlock::new(pc);
while !self.data.is_empty() {
block.push_instruction(self.decode()?);
}
self.block_decoding = false;
let instructions = block
.instructions
.into_iter()
.fold(vec![], |mut v, element| match element {
InstructionBlockElement::Label(_) => unreachable!(),
InstructionBlockElement::Instruction(i) => {
if self.labels.contains(&i.pc) {
v.push(InstructionBlockElement::Label(i.pc as u64));
}
v.push(element);
v
}
});
Ok(InstructionBlock::with_instructions(pc, instructions))
}
pub fn check_condition(&mut self, instruction: &mut Instruction) -> Result<()> {
match instruction.condition() {
ConditionalInstruction::ItBlock(cond, it_cond_1, it_cond_2, it_cond_3) => {
if self.it_block.is_some() {
todo!()
}
let states = [ItCondition::If, it_cond_1, it_cond_2, it_cond_3];
let count = states.iter().fold(0, |acc, c| {
acc + if *c == ItCondition::None { 0 } else { 1 }
});
self.it_block = Some(ItBlock {
condition: cond,
states,
index: 0,
count,
});
}
ConditionalInstruction::Condition(index, last_only, _settable) => {
if let Some(it_block) = &mut self.it_block {
match it_block.states[it_block.index] {
ItCondition::None => todo!(),
ItCondition::If => {
if last_only {
if it_block.index != it_block.states.len() - 1
&& !it_block.states[it_block.index + 1].is_none()
{
todo!()
}
}
let op = Operand::MnemonicCondition(it_block.condition.into());
instruction.set_op(index, op)?;
}
ItCondition::Else => {
if last_only {
if it_block.index != it_block.states.len() - 1
&& !it_block.states[it_block.index + 1].is_none()
{
todo!()
}
}
let op =
Operand::MnemonicCondition(it_block.condition.opposite().into());
instruction.set_op(index, op)?;
}
}
it_block.index += 1;
}
}
ConditionalInstruction::None => {
if let Some(it_block) = &mut self.it_block {
it_block.index += 1;
} else {
return Ok(());
}
}
}
let _ = self.it_block.take_if(|b| b.index == b.count);
Ok(())
}
}