2019-06-28 23:52:10 +01:00
|
|
|
use std::fmt;
|
|
|
|
|
2019-07-02 14:42:55 +01:00
|
|
|
use num::Num;
|
|
|
|
|
2019-06-23 00:57:14 +01:00
|
|
|
pub mod arm;
|
2019-07-02 14:57:35 +01:00
|
|
|
pub mod thumb;
|
|
|
|
|
2019-07-01 15:45:29 +01:00
|
|
|
use arm::{ArmDecodeError, ArmInstruction};
|
2019-07-02 14:57:35 +01:00
|
|
|
use thumb::{ThumbDecodeError, ThumbInstruction};
|
2019-06-28 23:52:10 +01:00
|
|
|
|
2019-06-25 00:10:09 +01:00
|
|
|
pub mod cpu;
|
2019-07-01 15:45:29 +01:00
|
|
|
pub use cpu::*;
|
2019-06-30 14:59:19 +01:00
|
|
|
pub mod bus;
|
2019-07-02 11:31:02 +01:00
|
|
|
pub use bus::Bus;
|
2019-07-02 14:42:55 +01:00
|
|
|
pub mod exception;
|
|
|
|
pub mod psr;
|
2019-06-27 13:13:38 +01:00
|
|
|
|
2019-06-24 18:20:08 +01:00
|
|
|
pub const REG_PC: usize = 15;
|
2019-06-28 09:46:36 +01:00
|
|
|
pub const REG_LR: usize = 14;
|
|
|
|
pub const REG_SP: usize = 13;
|
2019-06-24 18:20:08 +01:00
|
|
|
|
2019-06-30 14:59:19 +01:00
|
|
|
pub type Addr = u32;
|
|
|
|
|
2019-07-02 14:57:35 +01:00
|
|
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
|
|
|
pub enum DecodedInstruction {
|
|
|
|
Arm(ArmInstruction),
|
|
|
|
Thumb(ThumbInstruction),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DecodedInstruction {
|
|
|
|
pub fn get_pc(&self) -> Addr {
|
|
|
|
match self {
|
|
|
|
DecodedInstruction::Arm(a) => a.pc,
|
|
|
|
DecodedInstruction::Thumb(t) => t.pc,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl fmt::Display for DecodedInstruction {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
DecodedInstruction::Arm(a) => write!(f, "{}", a),
|
|
|
|
DecodedInstruction::Thumb(t) => write!(f, "{:#?}", t),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub enum InstructionDecoderError {
|
|
|
|
ArmDecodeError(ArmDecodeError),
|
|
|
|
ThumbDecodeError(ThumbDecodeError),
|
|
|
|
IoError(std::io::ErrorKind),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ArmDecodeError> for InstructionDecoderError {
|
|
|
|
fn from(e: ArmDecodeError) -> InstructionDecoderError {
|
|
|
|
InstructionDecoderError::ArmDecodeError(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ThumbDecodeError> for InstructionDecoderError {
|
|
|
|
fn from(e: ThumbDecodeError) -> InstructionDecoderError {
|
|
|
|
InstructionDecoderError::ThumbDecodeError(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait InstructionDecoder: Sized + fmt::Display {
|
|
|
|
type IntType: Num;
|
|
|
|
|
|
|
|
fn decode(n: Self::IntType, addr: Addr) -> Result<Self, InstructionDecoderError>;
|
|
|
|
/// Helper functions for the Disassembler
|
|
|
|
fn decode_from_bytes(bytes: &[u8], addr: Addr) -> Result<Self, InstructionDecoderError>;
|
|
|
|
fn get_raw(&self) -> Self::IntType;
|
|
|
|
}
|
|
|
|
|
2019-06-23 00:57:14 +01:00
|
|
|
pub fn reg_string(reg: usize) -> &'static str {
|
|
|
|
let reg_names = &[
|
2019-06-25 00:10:09 +01:00
|
|
|
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "fp", "ip", "sp", "lr",
|
|
|
|
"pc",
|
2019-06-23 00:57:14 +01:00
|
|
|
];
|
|
|
|
reg_names[reg]
|
|
|
|
}
|
|
|
|
|
2019-06-28 23:52:10 +01:00
|
|
|
#[derive(Debug, PartialEq, Primitive, Copy, Clone)]
|
|
|
|
#[repr(u8)]
|
|
|
|
pub enum CpuState {
|
|
|
|
ARM = 0,
|
|
|
|
THUMB = 1,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for CpuState {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
use CpuState::*;
|
|
|
|
match self {
|
|
|
|
ARM => write!(f, "ARM"),
|
|
|
|
THUMB => write!(f, "THUMB"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Primitive, Copy, Clone, PartialEq)]
|
|
|
|
pub enum CpuMode {
|
|
|
|
User = 0b10000,
|
|
|
|
Fiq = 0b10001,
|
|
|
|
Irq = 0b10010,
|
|
|
|
Supervisor = 0b10011,
|
|
|
|
Abort = 0b10111,
|
|
|
|
Undefined = 0b11011,
|
|
|
|
System = 0b11111,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CpuMode {
|
|
|
|
pub fn spsr_index(&self) -> Option<usize> {
|
|
|
|
match self {
|
|
|
|
CpuMode::Fiq => Some(0),
|
|
|
|
CpuMode::Irq => Some(1),
|
|
|
|
CpuMode::Supervisor => Some(2),
|
|
|
|
CpuMode::Abort => Some(3),
|
|
|
|
CpuMode::Undefined => Some(4),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn bank_index(&self) -> usize {
|
|
|
|
match self {
|
|
|
|
CpuMode::User | CpuMode::System => 0,
|
|
|
|
CpuMode::Fiq => 1,
|
|
|
|
CpuMode::Irq => 2,
|
|
|
|
CpuMode::Supervisor => 3,
|
|
|
|
CpuMode::Abort => 4,
|
|
|
|
CpuMode::Undefined => 5,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for CpuMode {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
use CpuMode::*;
|
|
|
|
match self {
|
|
|
|
User => write!(f, "USR"),
|
|
|
|
Fiq => write!(f, "FIQ"),
|
|
|
|
Irq => write!(f, "IRQ"),
|
|
|
|
Supervisor => write!(f, "SVC"),
|
|
|
|
Abort => write!(f, "ABT"),
|
|
|
|
Undefined => write!(f, "UND"),
|
|
|
|
System => write!(f, "SYS"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub enum CpuError {
|
2019-07-02 14:57:35 +01:00
|
|
|
DecodeError(InstructionDecoderError),
|
2019-06-28 23:52:10 +01:00
|
|
|
IllegalInstruction,
|
2019-07-02 14:57:35 +01:00
|
|
|
UnimplementedCpuInstruction(Addr, u32, DecodedInstruction),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<InstructionDecoderError> for CpuError {
|
|
|
|
fn from(e: InstructionDecoderError) -> CpuError {
|
|
|
|
CpuError::DecodeError(e)
|
|
|
|
}
|
2019-06-28 23:52:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ArmDecodeError> for CpuError {
|
|
|
|
fn from(e: ArmDecodeError) -> CpuError {
|
2019-07-02 14:57:35 +01:00
|
|
|
CpuError::DecodeError(InstructionDecoderError::ArmDecodeError(e))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ThumbDecodeError> for CpuError {
|
|
|
|
fn from(e: ThumbDecodeError) -> CpuError {
|
|
|
|
CpuError::DecodeError(InstructionDecoderError::ThumbDecodeError(e))
|
2019-06-28 23:52:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for CpuError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self {
|
2019-07-02 14:57:35 +01:00
|
|
|
CpuError::DecodeError(InstructionDecoderError::ArmDecodeError(e)) => write!(
|
2019-06-28 23:52:10 +01:00
|
|
|
f,
|
|
|
|
"arm decoding error at address @0x{:08x} (instruction 0x{:08x}): {:?}",
|
|
|
|
e.addr, e.insn, e.kind
|
|
|
|
),
|
2019-07-02 14:57:35 +01:00
|
|
|
CpuError::DecodeError(InstructionDecoderError::ThumbDecodeError(e)) => write!(
|
|
|
|
f,
|
|
|
|
"thumb decoding error at address @0x{:08x} (instruction 0x{:08x}): {:?}",
|
|
|
|
e.addr, e.insn, e.kind
|
|
|
|
),
|
|
|
|
CpuError::UnimplementedCpuInstruction(addr, raw, d) => write!(
|
2019-06-28 23:52:10 +01:00
|
|
|
f,
|
2019-07-02 14:57:35 +01:00
|
|
|
"unimplemented instruction: 0x{:08x}:\t0x{:08x}\t{:?}",
|
|
|
|
addr, raw, d
|
2019-06-28 23:52:10 +01:00
|
|
|
),
|
|
|
|
CpuError::IllegalInstruction => write!(f, "illegal instruction"),
|
|
|
|
e => write!(f, "error: {:#x?}", e),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub type CpuResult<T> = Result<T, CpuError>;
|
|
|
|
|
|
|
|
pub struct CpuModeContext {
|
|
|
|
// r8-r14
|
|
|
|
banked_gpr: [u32; 7],
|
|
|
|
spsr: u32,
|
|
|
|
}
|
|
|
|
|
2019-06-21 11:08:18 +01:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
#[test]
|
|
|
|
fn it_works() {
|
|
|
|
assert_eq!(2 + 2, 4);
|
|
|
|
}
|
|
|
|
}
|