Skip to content

Instantly share code, notes, and snippets.

@exjam
Created June 22, 2020 12:33
Show Gist options
  • Save exjam/aefbc69a877ff78878495dc1ee5875d1 to your computer and use it in GitHub Desktop.
Save exjam/aefbc69a877ff78878495dc1ee5875d1 to your computer and use it in GitHub Desktop.
#[macro_use]
extern crate bitfield;
#[macro_use] extern crate bitpat;
use std::io::prelude::*;
use std::fs::File;
use std::convert::TryInto;
use std::u32;
#[macro_use]
mod macros;
struct MemoryRegion {
name: &'static str,
start: usize,
end: usize,
size: usize,
data: Vec<u8>,
}
impl MemoryRegion {
pub fn new(name: &'static str, address: usize, size: usize, data: Option<Vec<u8>>) -> MemoryRegion {
let mut data = data.unwrap_or(Vec::with_capacity(size));
data.resize(size, 0);
MemoryRegion {
name: name,
start: address,
end: address + size,
size: size,
data: data
}
}
}
#[derive(Default)]
struct Memory {
regions: Vec<MemoryRegion>,
}
enum MemoryError
{
InvalidAddress
}
impl Memory {
pub fn new() -> Memory {
Default::default()
}
pub fn add_region(&mut self, name: &'static str, address: usize, size: usize, data: Option<Vec<u8>>) {
self.regions.push(MemoryRegion::new(name, address, size, data));
}
pub fn find_region(&self, address: usize) -> Result<&MemoryRegion, MemoryError> {
for region in &self.regions {
if address >= region.start && address < region.end {
return Ok(region)
}
}
return Err(MemoryError::InvalidAddress)
}
pub fn read_u32(&self, address: usize) -> Result<u32, MemoryError> {
let region = self.find_region(address)?;
let offset = address - region.start;
Ok(u32::from_be_bytes(region.data[offset .. offset+4].try_into().unwrap()))
}
}
mod armv5
{
use num_enum::TryFromPrimitive;
use std::convert::TryFrom;
#[derive(Debug,TryFromPrimitive)]
#[repr(u32)]
pub enum Condition {
Equal = 0b0000,
NotEqual = 0b0001,
UnsignedGreaterThanEqual = 0b0010,
UnsignedLessThan = 0b0011,
Negative = 0b0100,
Positive = 0b0101,
Overflow = 0b0110,
NoOverflow = 0b0111,
UnsignedGreaterThan = 0b1000,
UnsignedLessThanEqual = 0b1001,
SignedGreaterThanEqual = 0b1010,
SignedLessThan = 0b1011,
SignedGreaterThan = 0b1100,
SignedLessThanEqual = 0b1101,
Always = 0b1110,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Link(pub bool);
impl From<bool> for Link {
fn from(flag: bool) -> Self {
Link(flag)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct SetFlags(pub bool);
impl From<bool> for SetFlags {
fn from(flag: bool) -> Self {
SetFlags(flag)
}
}
#[derive(Debug)]
pub enum ShifterOperand {
Immediate {
rotate_imm: u8,
immed_8: u8,
},
ImmediateShift {
shift_imm: u8,
shift: u8,
rm: u8,
},
RegisterShift {
rs: u8,
shift: u8,
rm: u8,
}
}
#[derive(Debug)]
pub enum Instruction {
ADC { cond: Condition, s: bool, rn: u8, rd: u8, shifter_operand: ShifterOperand },
ADD { cond: Condition, s: bool, rn: u8, rd: u8, shifter_operand: ShifterOperand },
AND { cond: Condition, s: bool, rn: u8, rd: u8, shifter_operand: ShifterOperand },
B { cond: Condition, link: bool, signed_immed_24: i32 },
BIC { cond: Condition, s: bool, rn: u8, rd: u8, shifter_operand: ShifterOperand },
CMN { cond: Condition, rn: u8, shifter_operand: ShifterOperand },
CMP { cond: Condition, rn: u8, shifter_operand: ShifterOperand },
EOR { cond: Condition, s: bool, rn: u8, rd: u8, shifter_operand: ShifterOperand },
MOV { cond: Condition, s: bool, rd: u8, shifter_operand: ShifterOperand },
MCR { cond: Condition, opcode_1: u8, crn: u8, rd: u8, cp_num: u8, opcode_2: u8, crm: u8 },
MCR2 { opcode_1: u8, crn: u8, rd: u8, cp_num: u8, opcode_2: u8, crm: u8 },
MVN { cond: Condition, s: bool, rd: u8, shifter_operand: ShifterOperand },
ORR { cond: Condition, s: bool, rn: u8, rd: u8, shifter_operand: ShifterOperand },
RSB { cond: Condition, s: bool, rn: u8, rd: u8, shifter_operand: ShifterOperand },
RSC { cond: Condition, s: bool, rn: u8, rd: u8, shifter_operand: ShifterOperand },
SBC { cond: Condition, s: bool, rn: u8, rd: u8, shifter_operand: ShifterOperand },
SUB { cond: Condition, s: bool, rn: u8, rd: u8, shifter_operand: ShifterOperand },
TEQ { cond: Condition, rn: u8, shifter_operand: ShifterOperand },
TST { cond: Condition, rn: u8, shifter_operand: ShifterOperand },
}
pub enum DecoderError
{
InvalidInstruction,
}
impl From<num_enum::TryFromPrimitiveError<Condition>> for DecoderError {
fn from(_: num_enum::TryFromPrimitiveError<Condition>) -> Self {
DecoderError::InvalidInstruction
}
}
bitfield!{
pub struct CPSR(u32);
impl Debug;
pub get_thumb_mode, set_thumb_mode: 5;
}
pub struct State {
pub cpsr: CPSR
}
pub fn decode(state: &State, word: u32) -> Result<Instruction, DecoderError> {
if state.cpsr.get_thumb_mode() {
decode_thumb(word)
} else {
decode_armv5(word)
}
}
pub fn decode_armv5(word: u32) -> Result<Instruction, DecoderError> {
if bits!(word, 31, 28) == 0b1111 {
decode_armv5_unconditional(word)
} else {
match bits!(word, 27, 25) {
0b000 => {
if !bit!(word, 4) {
if bits!(word, 24, 23) == 0b10 && !bit!(word, 20) {
decode_armv5_miscellaneous(word)
} else {
decode_armv5_data_processing(word)
}
} else if !bit!(word, 7) {
if bits!(word, 24, 23) == 0b10 && !bit!(word, 20) {
decode_armv5_miscellaneous(word)
} else {
decode_armv5_data_processing(word)
}
} else {
decode_armv5_load_store_multiply_extension(word)
}
},
0b001 => {
if bits!(word, 24, 23) == 0b10 && !bit!(word, 20) {
if bit!(word, 21) {
Err(DecoderError::InvalidInstruction)
} else {
decode_armv5_move_immediate_status_register(word)
}
} else {
decode_armv5_data_processing(word)
}
},
0b010 => decode_armv5_load_store_immediate(word),
0b011 if !bit!(word, 4) => decode_armv5_load_store_register(word),
0b011 if bit!(word, 4) => decode_armv5_media(word),
0b011 if bits!(word, 24, 21) == 0b11111 && bits!(word, 7, 4) == 0b1111 => Err(DecoderError::InvalidInstruction),
0b100 => decode_armv5_load_store_multiple(word),
0b101 => decode_armv5_branch(word),
0b110 => decode_armv5_coprocessor_load_store(word),
0b111 if !bit!(word, 24) && !bit!(word, 4) => decode_armv5_coprocessor_data_processing(word),
0b111 if !bit!(word, 24) && bit!(word, 4) => decode_armv5_coprocessor_register_transfers(word),
0b111 if bit!(word, 24) => decode_armv5_software_interrupt(word),
_ => Err(DecoderError::InvalidInstruction),
}
}
}
pub fn decode_armv5_branch(word: u32) -> Result<Instruction, DecoderError> {
Ok(Instruction::B {
cond: Condition::try_from(bits!(word, 31, 28)) ?,
link: bit!(word, 24),
signed_immed_24: ((bits!(word, 23, 0) as i32) << 8) >> 6,
})
}
pub fn decode_armv5_coprocessor_data_processing(word: u32) -> Result<Instruction, DecoderError> {
Err(DecoderError::InvalidInstruction)
}
pub fn decode_armv5_coprocessor_load_store(word: u32) -> Result<Instruction, DecoderError> {
Err(DecoderError::InvalidInstruction)
}
pub fn decode_armv5_coprocessor_register_transfers(word: u32) -> Result<Instruction, DecoderError> {
if !bit!(word, 20) {
Ok(Instruction::MCR {
cond: Condition::try_from(bits!(word, 31, 28)) ?,
opcode_1: bits!(word, 23, 21) as u8,
crn: bits!(word, 19, 16) as u8,
rd: bits!(word, 15, 12) as u8,
cp_num: bits!(word, 11, 8) as u8,
opcode_2: bits!(word, 7, 5) as u8,
crm: bits!(word, 3, 0) as u8,
})
} else {
// LDC
Err(DecoderError::InvalidInstruction)
}
}
pub fn decode_armv5_data_processing(word: u32) -> Result<Instruction, DecoderError> {
let cond = Condition::try_from(bits!(word, 31, 28)) ?;
let opcode = bits!(word, 24, 21);
let s = bit!(word, 20);
let rn = bits!(word, 19, 16) as u8;
let rd = bits!(word, 15, 12) as u8;
let shifter_operand = if bit!(word, 25) {
ShifterOperand::Immediate {
rotate_imm: bits!(word, 11, 8) as u8,
immed_8: bits!(word, 7, 0) as u8,
}
} else if bit!(word, 4) {
ShifterOperand::RegisterShift {
rs: bits!(word, 11, 8) as u8,
shift: bits!(word, 6, 5) as u8,
rm: bits!(word, 3, 0) as u8,
}
} else {
ShifterOperand::ImmediateShift {
shift_imm: bits!(word, 11, 7) as u8,
shift: bits!(word, 6, 5) as u8,
rm: bits!(word, 3, 0) as u8,
}
};
match opcode {
0b0000 => Ok(Instruction::AND { cond: cond, s: s, rd: rd, rn: rn, shifter_operand: shifter_operand }),
0b0001 => Ok(Instruction::EOR { cond: cond, s: s, rd: rd, rn: rn, shifter_operand: shifter_operand }),
0b0010 => Ok(Instruction::SUB { cond: cond, s: s, rd: rd, rn: rn, shifter_operand: shifter_operand }),
0b0011 => Ok(Instruction::RSB { cond: cond, s: s, rd: rd, rn: rn, shifter_operand: shifter_operand }),
0b0100 => Ok(Instruction::ADD { cond: cond, s: s, rd: rd, rn: rn, shifter_operand: shifter_operand }),
0b0101 => Ok(Instruction::ADC { cond: cond, s: s, rd: rd, rn: rn, shifter_operand: shifter_operand }),
0b0110 => Ok(Instruction::SBC { cond: cond, s: s, rd: rd, rn: rn, shifter_operand: shifter_operand }),
0b0111 => Ok(Instruction::RSC { cond: cond, s: s, rd: rd, rn: rn, shifter_operand: shifter_operand }),
0b1000 => Ok(Instruction::TST { cond: cond, rn: rn, shifter_operand: shifter_operand }),
0b1001 => Ok(Instruction::TEQ { cond: cond, rn: rn, shifter_operand: shifter_operand }),
0b1010 => Ok(Instruction::CMP { cond: cond, rn: rn, shifter_operand: shifter_operand }),
0b1011 => Ok(Instruction::CMN { cond: cond, rn: rn, shifter_operand: shifter_operand }),
0b1100 => Ok(Instruction::ORR { cond: cond, s: s, rd: rd, rn: rn, shifter_operand: shifter_operand }),
0b1101 => Ok(Instruction::MOV { cond: cond, s: s, rd: rd, shifter_operand: shifter_operand }),
0b1110 => Ok(Instruction::BIC { cond: cond, s: s, rd: rd, rn: rn, shifter_operand: shifter_operand }),
0b1111 => Ok(Instruction::MVN { cond: cond, s: s, rd: rd, shifter_operand: shifter_operand }),
_ => Err(DecoderError::InvalidInstruction)
}
}
pub fn decode_armv5_load_store_immediate(word: u32) -> Result<Instruction, DecoderError> {
Err(DecoderError::InvalidInstruction)
}
pub fn decode_armv5_load_store_register(word: u32) -> Result<Instruction, DecoderError> {
Err(DecoderError::InvalidInstruction)
}
pub fn decode_armv5_load_store_multiple(word: u32) -> Result<Instruction, DecoderError> {
Err(DecoderError::InvalidInstruction)
}
pub fn decode_armv5_load_store_multiply_extension(word: u32) -> Result<Instruction, DecoderError> {
Err(DecoderError::InvalidInstruction)
}
pub fn decode_armv5_media(word: u32) -> Result<Instruction, DecoderError> {
Err(DecoderError::InvalidInstruction)
}
pub fn decode_armv5_miscellaneous(word: u32) -> Result<Instruction, DecoderError> {
Err(DecoderError::InvalidInstruction)
}
pub fn decode_armv5_move_immediate_status_register(word: u32) -> Result<Instruction, DecoderError> {
Err(DecoderError::InvalidInstruction)
}
pub fn decode_armv5_software_interrupt(word: u32) -> Result<Instruction, DecoderError> {
Err(DecoderError::InvalidInstruction)
}
pub fn decode_armv5_unconditional(word: u32) -> Result<Instruction, DecoderError> {
Err(DecoderError::InvalidInstruction)
}
pub fn decode_thumb(word: u32) -> Result<Instruction, DecoderError> {
Err(DecoderError::InvalidInstruction)
}
}
fn main() -> std::io::Result<()> {
let mut f = File::open("boot0.bin")?;
let mut boot0 = Vec::new();
f.read_to_end(&mut boot0)?;
let mut f = File::open("boot1.bin")?;
let mut boot1 = Vec::new();
f.read_to_end(&mut boot1)?;
let mut memory = Memory::new();
memory.add_region("SRAM0", 0x0D410000, 0x10000, None);
memory.add_region("SRAM1", 0x0D400000, 0x10000, None);
memory.add_region("BOOT0_ROM", 0xFFFF0000, 0x4000, Some(boot0));
memory.add_region("BOOT1_ROM", 0xFFF00000, 0xF800, Some(boot1));
let insn = memory.read_u32(0xFFFF00A4).unwrap_or(0);
println!("First instruction: {:08X}", insn);
let mut state = armv5::State {
cpsr: armv5::CPSR(0)
};
let decoded = armv5::decode(&state, insn);
println!("{:#?}", decoded.ok().unwrap());
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment