superh 0.2.2

Disassembler for the SuperH (SH) instruction set (SH1/2/3/4)
Documentation
use superh::{Address, Architecture, ControlFlow, DecodeOptions, Ins, decode};

fn instruction(word: u16) -> Ins {
    decode(word, &DecodeOptions::new(Architecture::default()))
        .instruction()
        .cloned()
        .expect("known instruction")
}

#[test]
fn classifies_control_flow_and_delay_slots() {
    assert_eq!(
        instruction(0xa000).control_flow(),
        ControlFlow::Direct { call: false, delay_slot: true }
    );
    assert_eq!(
        instruction(0xb000).control_flow(),
        ControlFlow::Direct { call: true, delay_slot: true }
    );
    assert_eq!(instruction(0x8900).control_flow(), ControlFlow::Conditional { delay_slot: false });
    assert!(instruction(0x402b).has_delay_slot());
    assert!(!instruction(0x8900).has_delay_slot());
    assert!(!instruction(0x0009).is_branch());
}

#[test]
fn resolves_positive_and_negative_direct_branches() {
    assert_eq!(instruction(0x8903).at(0).branch_target(), Some(Address::new(10)));
    assert_eq!(instruction(0x8bfe).at(0).branch_target(), Some(Address::new(0)));
    assert_eq!(
        instruction(0xa000).at(0x8c01_0000).branch_target(),
        Some(Address::new(0x8c01_0004))
    );
}

#[test]
fn branch_resolution_wraps_in_the_32_bit_address_space() {
    assert_eq!(instruction(0x8900).at(0xffff_fffe).branch_target(), Some(Address::new(2)));
}

#[test]
fn resolves_pc_relative_literal_addresses() {
    assert_eq!(instruction(0x9001).at(0x1002).pc_relative_address(), Some(Address::new(0x1008)));
    assert_eq!(instruction(0xd001).at(0x1002).pc_relative_address(), Some(Address::new(0x1008)));
    assert_eq!(instruction(0xc701).at(0x1002).pc_relative_address(), Some(Address::new(0x1008)));
}