use super::instruction::*;
use super::operand::*;
use crate::error::Result;
use std::collections::HashMap;
pub(crate) mod encoder;
pub struct Encoder {
data: Vec<u8>,
it_block: Option<ItBlock>,
}
impl Encoder {
pub fn new() -> Self {
Self {
data: vec![],
it_block: None,
}
}
pub fn encode(&mut self, instr: &Instruction) -> Result<usize> {
self.check_condition(instr)?;
encoder::encode(instr, &mut self.data)
}
pub(crate) fn encode_block(
&mut self,
instr: &mut Instruction,
labels: &HashMap<u64, u64>,
) -> Result<usize> {
encoder::encode_block(instr, &mut self.data, labels)
}
pub fn check_condition(&mut self, instruction: &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) => {
let condition = instruction.get_op(index).as_mnemonic_condition()?;
let condition: Condition = (*condition).into();
if let Some(it_block) = &mut self.it_block {
match it_block.states[it_block.index] {
ItCondition::None => todo!(),
ItCondition::If => {
if condition != it_block.condition {
todo!()
}
}
ItCondition::Else => {
if condition != it_block.condition.opposite() {
todo!()
}
}
}
it_block.index += 1;
}
}
ConditionalInstruction::None => {
}
}
let _ = self.it_block.take_if(|b| b.index == b.count);
Ok(())
}
pub fn take(self) -> Vec<u8> {
self.data
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct EncoderBlock {
blocks: Vec<InstructionBlock>,
}
impl EncoderBlock {
pub fn new(instr_blocks: Vec<InstructionBlock>) -> Self {
Self {
blocks: instr_blocks,
}
}
pub fn encode(mut self) -> Result<Vec<EncoderBlockResult>> {
let mut labels = HashMap::new();
for block in self.blocks.iter_mut() {
let mut pc = block.pc as u32;
for element in block.instructions.iter_mut() {
match element {
InstructionBlockElement::Label(label) => {
if labels.insert(*label, pc as u64).is_some() {
todo!()
}
}
InstructionBlockElement::Instruction(instruction) => {
instruction.pc = pc;
pc += instruction.size as u32;
}
}
}
}
self.blocks
.into_iter()
.map(|block| -> Result<EncoderBlockResult> {
let mut encoder = Encoder::new();
for element in block.instructions.into_iter() {
if let InstructionBlockElement::Instruction(mut instruction) = element {
let _ = encoder.encode_block(&mut instruction, &labels)?;
}
}
Ok(EncoderBlockResult {
pc: block.pc,
data: encoder.take(),
})
})
.collect()
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct EncoderBlockResult {
pub pc: u32,
pub data: Vec<u8>,
}
#[cfg(test)]
mod test {
use super::*;
use crate::core::t32::config::*;
use crate::core::t32::consts::*;
use crate::core::t32::formatter::*;
use rhexdump::rhexdump;
#[test]
pub fn blocks() {
let instructions: Vec<InstructionBlockElement> = vec![
1.into(),
Instruction::with_encoding_4(
Code::AND_r_T2,
Encoding::Alt2,
MnemonicCondition::Al,
Register::R0,
Register::R1,
Register::R2,
)
.unwrap()
.into(),
Instruction::with_3(
Code::ADR_T2,
MnemonicCondition::Al,
Register::R0,
Label::LabelName(1),
)
.unwrap()
.into(),
Instruction::with_3(
Code::ADR_T1,
MnemonicCondition::Al,
Register::R0,
Label::LabelName(3),
)
.unwrap()
.into(),
2.into(),
];
let instructions2: Vec<InstructionBlockElement> = vec![
3.into(),
Instruction::with_4(
Code::IT_T1,
ItCondition::Else,
ItCondition::None,
ItCondition::None,
Condition::Eq,
)
.unwrap()
.into(),
Instruction::with_3(
Code::ADR_T2,
MnemonicCondition::Al,
Register::R0,
Label::LabelName(2),
)
.unwrap()
.into(),
Instruction::with_3(
Code::ADR_T1,
MnemonicCondition::Al,
Register::R0,
Label::LabelName(4),
)
.unwrap()
.into(),
4.into(),
Instruction::with_3(
Code::ADR_T2,
MnemonicCondition::Al,
Register::R0,
Label::LabelName(3),
)
.unwrap()
.into(),
];
let block = InstructionBlock::with_instructions(0xdead0000, instructions);
let block2 = InstructionBlock::with_instructions(0xdead0200, instructions2);
let encoder_block = EncoderBlock::new(vec![block, block2]);
let block = encoder_block.encode().unwrap();
rhexdump!(&block[0].data, 0xdead0000);
rhexdump!(&block[1].data, 0xdead0200);
let config = ConfigLLVM::new();
let mut insn = Instruction::with_3(
Code::ADR_T1,
MnemonicCondition::Al,
Register::R0,
Label::Label(24),
)
.unwrap();
let mut formatter = Fmt {};
let mut output = String::new();
insn.pc = 0xdead0000;
formatter.format(&mut output, &config, &insn).unwrap();
println!("{}", output);
}
}