use crate::bits::BitReader;
use crate::test_binary::{
Abort, RelayAction, RelayInstr, Segment, SensorAction, SensorInstr, Test, TestBody,
};
use crate::{result::CompilerResult, test_binary::DeviceAddress};
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
pub fn emit(test: Test, output_path: Option<PathBuf>) -> CompilerResult<()> {
let mut res = CompilerResult::status_only("Emitting TAF");
let mut file = check!(
res,
File::create(output_path.unwrap_or_else(|| "./a.taf".into()))
);
let taf_string = check!(res, test.disassemble());
check!(res, file.write(taf_string.as_bytes()));
res
}
pub fn disassemble_tbf(path: PathBuf) -> CompilerResult<Test> {
let mut res = CompilerResult::new("Test disassembly");
let mut tbf_reader = check!(res, BitReader::from_file(path));
tbf_reader.skip(704);
let aborts = check!(res, disassemble_aborts(&mut tbf_reader));
let body = check!(res, disassemble_test_body(&mut tbf_reader));
let test = Test { aborts, body };
res.with_value(test)
}
fn disassemble_aborts(tbf_reader: &mut BitReader) -> CompilerResult<[Abort; 15]> {
let mut res = CompilerResult::new("Abort disassembly");
let mut aborts = [
Abort::new(),
Abort::new(),
Abort::new(),
Abort::new(),
Abort::new(),
Abort::new(),
Abort::new(),
Abort::new(),
Abort::new(),
Abort::new(),
Abort::new(),
Abort::new(),
Abort::new(),
Abort::new(),
Abort::new(),
];
for _i in 0..15 {
if check!(res, tbf_reader.read_u8(8), "Couldn't read abort prefix") != 0xF0u8 {
res.error("Invalid abort prefix");
}
let abort_idx = check!(res, tbf_reader.read_u8(8), "Couldn't read abort idx");
let section_length = check!(
res,
tbf_reader.read_u16(16),
"Couldn't read abort section length"
);
let section_end = tbf_reader.remaining_len() + 32 - (section_length * 8) as usize;
check!(
res,
disassemble_section(
tbf_reader,
&mut aborts[abort_idx as usize - 1].segments,
section_end as usize,
)
);
}
res.with_value(aborts)
}
fn disassemble_test_body(tbf_reader: &mut BitReader) -> CompilerResult<TestBody> {
let mut res = CompilerResult::new("Test body disassembly");
let mut test_body = TestBody::new();
let body_prefix = check!(
res,
tbf_reader.read_u8(8),
"Couldn't ready test body prefix"
);
if body_prefix != 0xF1u8 {
res.error("Invalid test body header byte!");
return res;
}
let body_length = check!(
res,
tbf_reader.read_u32(24),
"Couldn't read test body length"
);
let section_end = tbf_reader.remaining_len() + 32 - (body_length * 8) as usize;
check!(
res,
disassemble_section(tbf_reader, &mut test_body.segments, section_end)
);
res.with_value(test_body)
}
fn disassemble_section(
tbf_reader: &mut BitReader,
input_vector: &mut Vec<Segment>,
section_end: usize,
) -> CompilerResult<()> {
let mut res = CompilerResult::status_only("Disassembling segments within test body or abort.");
while tbf_reader.remaining_len() > section_end {
if (check!(res, tbf_reader.read_u8(3), "Couldn't read segment prefix.") == 0b000) {
input_vector.push(check!(res, disassemble_segment(tbf_reader)));
} else {
res.error("Invalid segment prefix!");
return res;
}
}
res
}
fn disassemble_segment(tbf_reader: &mut BitReader) -> CompilerResult<Segment> {
let mut res = CompilerResult::new("Segment disassembly");
let _z = check!(res, tbf_reader.read_u8(1), "Couldn't read segment z");
let relative_time = check!(
res,
tbf_reader.read_u32(20),
"Couldn't read segment relative time"
);
let num_sensors = check!(
res,
tbf_reader.read_u16(16),
"Couldn't read number of sensor instructions in segment"
);
let num_relays = check!(
res,
tbf_reader.read_u16(16),
"Couldn't read number of relay instructions in segment"
);
let mut segment = check!(res, Segment::try_new(relative_time as u32));
for _i in 0..(num_relays + num_sensors) {
let prefix = check!(
res,
tbf_reader.read_u8(3),
"Couldn't read instruction prefix for segment."
);
match prefix {
0b010 => segment
.sensor_instructions
.push(check!(res, disassemble_sensor_instr(tbf_reader))),
0b001 => segment
.relay_instructions
.push(check!(res, disassemble_relay_instr(tbf_reader))),
_ => {
res.error("Invalid instruction prefix!");
return res;
}
}
}
res.with_value(segment)
}
fn disassemble_sensor_instr(tbf_reader: &mut BitReader) -> CompilerResult<SensorInstr> {
let mut res = CompilerResult::new("Sensor Instruction disassembly");
let opcode = check!(
res,
tbf_reader.read_u8(6),
"Couldn't read sensor instruction opcode"
);
let action = match opcode {
0b000000 => SensorAction::stop_check,
0b000001 => SensorAction::start_check_in,
0b111111 => SensorAction::is_now_in,
_ => {
res.error("Invalid sensor opcode!");
return res;
}
};
let abort_idx = check!(
res,
tbf_reader.read_u8(4),
"Couldn't read sensor instruction abort index"
);
let virtuality = check!(
res,
tbf_reader.read_u16(1),
"Couldn't read sensor instruction virtuality"
);
let device_address = check!(
res,
tbf_reader.read_u16(10),
"Couldn't read sensor instruction device address"
);
let device_address = DeviceAddress {
value: device_address,
virtuality,
};
let left_bound = check!(res, tbf_reader.read_u16(12), "Couldn't read left bound");
let right_bound = check!(res, tbf_reader.read_u16(12), "Couldn't read right bound");
let sensor_instr = check!(
res,
SensorInstr::try_new(action, abort_idx, device_address, left_bound, right_bound)
);
res.with_value(sensor_instr)
}
fn disassemble_relay_instr(tbf_reader: &mut BitReader) -> CompilerResult<RelayInstr> {
let mut res = CompilerResult::new("Relay Instruction disassembly");
let opcode = check!(
res,
tbf_reader.read_u8(2),
"Couldn't read relay instruction opcode"
);
let action = match opcode {
0b0 => RelayAction::Set,
0b1 => RelayAction::Unset,
_ => {
res.error("Invalid relay opcode!");
return res;
}
};
let virtuality = check!(
res,
tbf_reader.read_u16(1),
"Couldn't read relay instruction virtuality"
);
let device_address = check!(
res,
tbf_reader.read_u16(10),
"Couldn't read relay instruction device address"
);
let device_address = DeviceAddress {
value: device_address,
virtuality,
};
let relay_instr = check!(res, RelayInstr::try_new(action, device_address));
res.with_value(relay_instr)
}