/*
    This file is part of r2-c166.

    r2-c166 is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    r2-c166 is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with r2-c166.  If not, see <http://www.gnu.org/licenses/>.
*/

use std::str::FromStr;
use ::instruction::*;
use std::fmt;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Reg {
    R0,
    R1,
    R2,
    R3,
    R4,
    R5,
    R6,
    R7,
    R8,
    R9,
    R10,
    R11,
    R12,
    R13,
    R14,
    R15,

    RL0,
    RH0,
    RL1,
    RH1,
    RL2,
    RH2,
    RL3,
    RH3,
    RL4,
    RH4,
    RL5,
    RH5,
    RL6,
    RH6,
    RL7,
    RH7,

    ADCIC,
    ADCON,
    ADDAT,
    ADDRSEL1,
    ADDRSEL2,
    ADDRSEL3,
    ADDRSEL4,
    ADEIC,
    BUSCON0,
    BUSCON1,
    BUSCON2,
    BUSCON3,
    BUSCON4,
    C1UMLM, // No 8-bit addr
    C1UGML, // No 8-bit addr
    C1LMLM, // No 8-bit addr
    C1LGML, // No 8-bit addr
    C1IR, // No 8-bit addr
    C1GMS, // No 8-bit addr
    C1BTR, // No 8-bit addr
    C1CSR, // No 8-bit addr
    CAPREL,
    CC0,
    CC0IC,
    CC1,
    CC1IC,
    CC2,
    CC2IC,
    CC3,
    CC3IC,
    CC4,
    CC4IC,
    CC5,
    CC5IC,
    CC6,
    CC6IC,
    CC7,
    CC7IC,
    CC8,
    CC8IC,
    CC9,
    CC9IC,
    CC10,
    CC10IC,
    CC11,
    CC11IC,
    CC12,
    CC12IC,
    CC13,
    CC13IC,
    CC14,
    CC14IC,
    CC15,
    CC15IC,
    CC16,
    CC17,
    CC18,
    CC19,
    CC20,
    CC21,
    CC22,
    CC23,
    CC24,
    CC25,
    CC26,
    CC27,
    CC28,
    CC29,
    CC30,
    CC31,
    CCM0,
    CCM1,
    CCM2,
    CCM3,
    CCM4,
    CCM5,
    CCM6,
    CCM7,
    CP,
    CRIC,
    CSP,
    DP2,
    DP3,
    DP4,
    DP6,
    DP7,
    DP8,
    DPP0,
    DPP1,
    DPP2,
    DPP3,
    MDC,
    MDH,
    MDL,
    ONES,
    P0L,
    P0H,
    P1L,
    P1H,
    P2,
    P3,
    P4,
    P5,
    P6,
    P7,
    P8,
    PECC0,
    PECC1,
    PECC2,
    PECC3,
    PECC4,
    PECC5,
    PECC6,
    PECC7,
    PSW,
    PW0,
    PW1,
    PW2,
    PW3,
    PWMCON0,
    PWMCON1,
    S0BG,
    S0CON,
    S0EIC,
    S0RBUF,
    S0RIC,
    S0TBUF,
    S0TIC,
    SP,
    SSCCON,
    SSCEIC,
    SSCRIC,
    SSCTIC,
    STKOV,
    STKUN,
    SYSCON,
    T0,
    T01CON,
    T0IC,
    T0REL,
    T1,
    T1IC,
    T1REL,
    T2,
    T2CON,
    T2IC,
    T3,
    T3CON,
    T3IC,
    T4,
    T4CON,
    T4IC,
    T5,
    T5CON,
    T5IC,
    T6,
    T6CON,
    T6IC,
    T78CON,
    TFR,
    WDT,
    WDTCON,
    ZEROS,

    ADDAT2,
    CC16IC,
    CC17IC,
    CC18IC,
    CC19IC,
    CC20IC,
    CC21IC,
    CC22IC,
    CC23IC,
    CC24IC,
    CC25IC,
    CC26IC,
    CC27IC,
    CC28IC,
    CC29IC,
    CC30IC,
    CC31IC,
    DP0L,
    DP0H,
    DP1L,
    DP1H,
    EXICON,
    ODP2,
    ODP3,
    ODP6,
    ODP7,
    ODP8,
    PICON,
    PP0,
    PP1,
    PP2,
    PP3,
    PT0,
    PT1,
    PT2,
    PT3,
    PWMIC,
    RP0H,
    S0TBIC,
    SSCBR,
    SSCRB,
    SSCTB,
    T7,
    T7IC,
    T7REL,
    T8,
    T8IC,
    T8REL,
    XP0IC,
    XP1IC,
    XP2IC,
    XP3IC,

    SFR(u8),
    ESFR(u8),
}

impl Reg {
    pub fn to_reg4(&self) -> Result<u8, &'static str> {
        match *self {
            Reg::R0 => Ok(0x0),
            Reg::R1 => Ok(0x1),
            Reg::R2 => Ok(0x2),
            Reg::R3 => Ok(0x3),
            Reg::R4 => Ok(0x4),
            Reg::R5 => Ok(0x5),
            Reg::R6 => Ok(0x6),
            Reg::R7 => Ok(0x7),
            Reg::R8 => Ok(0x8),
            Reg::R9 => Ok(0x9),
            Reg::R10 => Ok(0xA),
            Reg::R11 => Ok(0xB),
            Reg::R12 => Ok(0xC),
            Reg::R13 => Ok(0xD),
            Reg::R14 => Ok(0xE),
            Reg::R15 => Ok(0xF),
            Reg::RL0 => Ok(0x0),
            Reg::RH0 => Ok(0x1),
            Reg::RL1 => Ok(0x2),
            Reg::RH1 => Ok(0x3),
            Reg::RL2 => Ok(0x4),
            Reg::RH2 => Ok(0x5),
            Reg::RL3 => Ok(0x6),
            Reg::RH3 => Ok(0x7),
            Reg::RL4 => Ok(0x8),
            Reg::RH4 => Ok(0x9),
            Reg::RL5 => Ok(0xA),
            Reg::RH5 => Ok(0xB),
            Reg::RL6 => Ok(0xC),
            Reg::RH6 => Ok(0xD),
            Reg::RL7 => Ok(0xE),
            Reg::RH7 => Ok(0xF),
            _ => Err("Register is not a GPR"),
        }
    }

    pub fn to_reg8(&self) -> Result<u8, &'static str> {
        match *self {
            Reg::R0 => Ok(0xF0),
            Reg::R1 => Ok(0xF1),
            Reg::R2 => Ok(0xF2),
            Reg::R3 => Ok(0xF3),
            Reg::R4 => Ok(0xF4),
            Reg::R5 => Ok(0xF5),
            Reg::R6 => Ok(0xF6),
            Reg::R7 => Ok(0xF7),
            Reg::R8 => Ok(0xF8),
            Reg::R9 => Ok(0xF9),
            Reg::R10 => Ok(0xFA),
            Reg::R11 => Ok(0xFB),
            Reg::R12 => Ok(0xFC),
            Reg::R13 => Ok(0xFD),
            Reg::R14 => Ok(0xFE),
            Reg::R15 => Ok(0xFF),

            Reg::RL0 => Ok(0xF0),
            Reg::RH0 => Ok(0xF1),
            Reg::RL1 => Ok(0xF2),
            Reg::RH1 => Ok(0xF3),
            Reg::RL2 => Ok(0xF4),
            Reg::RH2 => Ok(0xF5),
            Reg::RL3 => Ok(0xF6),
            Reg::RH3 => Ok(0xF7),
            Reg::RL4 => Ok(0xF8),
            Reg::RH4 => Ok(0xF9),
            Reg::RL5 => Ok(0xFA),
            Reg::RH5 => Ok(0xFB),
            Reg::RL6 => Ok(0xFC),
            Reg::RH6 => Ok(0xFD),
            Reg::RL7 => Ok(0xFE),
            Reg::RH7 => Ok(0xFF),

            Reg::ADCIC => Ok(0xCC),
            Reg::ADCON => Ok(0xD0),
            Reg::ADDAT => Ok(0x50),
            Reg::ADDRSEL1 => Ok(0x0C),
            Reg::ADDRSEL2 => Ok(0x0D),
            Reg::ADDRSEL3 => Ok(0x0E),
            Reg::ADDRSEL4 => Ok(0x0F),
            Reg::ADEIC => Ok(0xCD),
            Reg::BUSCON0 => Ok(0x86),
            Reg::BUSCON1 => Ok(0x8A),
            Reg::BUSCON2 => Ok(0x8B),
            Reg::BUSCON3 => Ok(0x8C),
            Reg::BUSCON4 => Ok(0x8D),
            Reg::CAPREL => Ok(0x25),
            Reg::CC0 => Ok(0x40),
            Reg::CC0IC => Ok(0xBC),
            Reg::CC1 => Ok(0x41),
            Reg::CC1IC => Ok(0xBD),
            Reg::CC2 => Ok(0x42),
            Reg::CC2IC => Ok(0xBE),
            Reg::CC3 => Ok(0x43),
            Reg::CC3IC => Ok(0xBF),
            Reg::CC4 => Ok(0x44),
            Reg::CC4IC => Ok(0xC0),
            Reg::CC5 => Ok(0x45),
            Reg::CC5IC => Ok(0xC1),
            Reg::CC6 => Ok(0x46),
            Reg::CC6IC => Ok(0xC2),
            Reg::CC7 => Ok(0x47),
            Reg::CC7IC => Ok(0xC3),
            Reg::CC8 => Ok(0x48),
            Reg::CC8IC => Ok(0xC4),
            Reg::CC9 => Ok(0x49),
            Reg::CC9IC => Ok(0xC5),
            Reg::CC10 => Ok(0x4A),
            Reg::CC10IC => Ok(0xC6),
            Reg::CC11 => Ok(0x4B),
            Reg::CC11IC => Ok(0xC7),
            Reg::CC12 => Ok(0x4C),
            Reg::CC12IC => Ok(0xC8),
            Reg::CC13 => Ok(0x4D),
            Reg::CC13IC => Ok(0xC9),
            Reg::CC14 => Ok(0x4E),
            Reg::CC14IC => Ok(0xCA),
            Reg::CC15 => Ok(0x4F),
            Reg::CC15IC => Ok(0xCB),
            Reg::CC16 => Ok(0x30),
            Reg::CC17 => Ok(0x31),
            Reg::CC18 => Ok(0x32),
            Reg::CC19 => Ok(0x33),
            Reg::CC20 => Ok(0x34),
            Reg::CC21 => Ok(0x35),
            Reg::CC22 => Ok(0x36),
            Reg::CC23 => Ok(0x37),
            Reg::CC24 => Ok(0x38),
            Reg::CC25 => Ok(0x39),
            Reg::CC26 => Ok(0x3A),
            Reg::CC27 => Ok(0x3B),
            Reg::CC28 => Ok(0x3C),
            Reg::CC29 => Ok(0x3D),
            Reg::CC30 => Ok(0x3E),
            Reg::CC31 => Ok(0x3F),
            Reg::CCM0 => Ok(0xA9),
            Reg::CCM1 => Ok(0xAA),
            Reg::CCM2 => Ok(0xAB),
            Reg::CCM3 => Ok(0xAC),
            Reg::CCM4 => Ok(0x91),
            Reg::CCM5 => Ok(0x92),
            Reg::CCM6 => Ok(0x93),
            Reg::CCM7 => Ok(0x94),
            Reg::CP => Ok(0x08),
            Reg::CRIC => Ok(0xB5),
            Reg::CSP => Ok(0x04),
            Reg::DP2 => Ok(0xE1),
            Reg::DP3 => Ok(0xE3),
            Reg::DP4 => Ok(0xE5),
            Reg::DP6 => Ok(0xE7),
            Reg::DP7 => Ok(0xE9),
            Reg::DP8 => Ok(0xEB),
            Reg::DPP0 => Ok(0x00),
            Reg::DPP1 => Ok(0x01),
            Reg::DPP2 => Ok(0x02),
            Reg::DPP3 => Ok(0x03),
            Reg::MDC => Ok(0x87),
            Reg::MDH => Ok(0x06),
            Reg::MDL => Ok(0x07),
            Reg::ONES => Ok(0x8F),
            Reg::P0L => Ok(0x80),
            Reg::P0H => Ok(0x81),
            Reg::P1L => Ok(0x82),
            Reg::P1H => Ok(0x83),
            Reg::P2 => Ok(0xE0),
            Reg::P3 => Ok(0xE2),
            Reg::P4 => Ok(0xE4),
            Reg::P5 => Ok(0xD1),
            Reg::P6 => Ok(0xE6),
            Reg::P7 => Ok(0xE8),
            Reg::P8 => Ok(0xEA),
            Reg::PECC0 => Ok(0x60),
            Reg::PECC1 => Ok(0x61),
            Reg::PECC2 => Ok(0x62),
            Reg::PECC3 => Ok(0x63),
            Reg::PECC4 => Ok(0x64),
            Reg::PECC5 => Ok(0x65),
            Reg::PECC6 => Ok(0x66),
            Reg::PECC7 => Ok(0x67),
            Reg::PSW => Ok(0x88),
            Reg::PW0 => Ok(0x18),
            Reg::PW1 => Ok(0x19),
            Reg::PW2 => Ok(0x1A),
            Reg::PW3 => Ok(0x1B),
            Reg::PWMCON0 => Ok(0x98),
            Reg::PWMCON1 => Ok(0x99),
            Reg::S0BG => Ok(0x5A),
            Reg::S0CON => Ok(0xD8),
            Reg::S0EIC => Ok(0xB8),
            Reg::S0RBUF => Ok(0x59),
            Reg::S0RIC => Ok(0xB7),
            Reg::S0TBUF => Ok(0x58),
            Reg::S0TIC => Ok(0xB6),
            Reg::SP => Ok(0x09),
            Reg::SSCCON => Ok(0xD9),
            Reg::SSCEIC => Ok(0xBB),
            Reg::SSCRIC => Ok(0xBA),
            Reg::SSCTIC => Ok(0xB9),
            Reg::STKOV => Ok(0x0A),
            Reg::STKUN => Ok(0x0B),
            Reg::SYSCON => Ok(0x89),
            Reg::T0 => Ok(0x28),
            Reg::T01CON => Ok(0xA8),
            Reg::T0IC => Ok(0xCE),
            Reg::T0REL => Ok(0x2A),
            Reg::T1 => Ok(0x29),
            Reg::T1IC => Ok(0xCF),
            Reg::T1REL => Ok(0x2B),
            Reg::T2 => Ok(0x20),
            Reg::T2CON => Ok(0xA0),
            Reg::T2IC => Ok(0xB0),
            Reg::T3 => Ok(0x21),
            Reg::T3CON => Ok(0xA1),
            Reg::T3IC => Ok(0xB1),
            Reg::T4 => Ok(0x22),
            Reg::T4CON => Ok(0xA2),
            Reg::T4IC => Ok(0xB2),
            Reg::T5 => Ok(0x23),
            Reg::T5CON => Ok(0xA3),
            Reg::T5IC => Ok(0xB3),
            Reg::T6 => Ok(0x24),
            Reg::T6CON => Ok(0xA4),
            Reg::T6IC => Ok(0xB4),
            Reg::T78CON => Ok(0x90),
            Reg::TFR => Ok(0xD6),
            Reg::WDT => Ok(0x57),
            Reg::WDTCON => Ok(0xD7),
            Reg::ZEROS => Ok(0x8E),

            Reg::SFR(r) => Ok(r),
            Reg::ESFR(r) => Ok(r),

            _ => Err("Unknown register"),
        }
    }

    pub fn to_phys16(&self) -> Result<u16, &'static str> {
        Err("Not Yer")
    }

    pub fn from_reg4(reg: u8, reg_type: &OperandType) -> Result<Reg, ()> {
        match reg_type {
            OperandType::ByteRegister(_) => {
                match reg {
                    0x0 => Ok(Reg::RL0),
                    0x1 => Ok(Reg::RH0),
                    0x2 => Ok(Reg::RL1),
                    0x3 => Ok(Reg::RH1),
                    0x4 => Ok(Reg::RL2),
                    0x5 => Ok(Reg::RH2),
                    0x6 => Ok(Reg::RL3),
                    0x7 => Ok(Reg::RH3),
                    0x8 => Ok(Reg::RL4),
                    0x9 => Ok(Reg::RH4),
                    0xA => Ok(Reg::RL5),
                    0xB => Ok(Reg::RH5),
                    0xC => Ok(Reg::RL6),
                    0xD => Ok(Reg::RH6),
                    0xE => Ok(Reg::RL7),
                    0xF => Ok(Reg::RH7),
                    _   => Err(())
                }
            },
            OperandType::WordRegister(_) => {
                match reg {
                    0x0 => Ok(Reg::R0),
                    0x1 => Ok(Reg::R1),
                    0x2 => Ok(Reg::R2),
                    0x3 => Ok(Reg::R3),
                    0x4 => Ok(Reg::R4),
                    0x5 => Ok(Reg::R5),
                    0x6 => Ok(Reg::R6),
                    0x7 => Ok(Reg::R7),
                    0x8 => Ok(Reg::R8),
                    0x9 => Ok(Reg::R9),
                    0xA => Ok(Reg::R10),
                    0xB => Ok(Reg::R11),
                    0xC => Ok(Reg::R12),
                    0xD => Ok(Reg::R13),
                    0xE => Ok(Reg::R14),
                    0xF => Ok(Reg::R15),
                    _   => Err(())
                }
            },
            _ => Err(())
        }
    }


    pub fn from_reg8(reg: u8, reg_type: &OperandType) -> Result<Reg, ()> {
        match reg_type {
            &OperandType::ExtendedRegister => {
                match reg {
                    0x50 => Ok(Reg::ADDAT2),
                    0xB0 => Ok(Reg::CC16IC),
                    0xB1 => Ok(Reg::CC17IC),
                    0xB2 => Ok(Reg::CC18IC),
                    0xB3 => Ok(Reg::CC19IC),
                    0xB4 => Ok(Reg::CC20IC),
                    0xB5 => Ok(Reg::CC21IC),
                    0xB6 => Ok(Reg::CC22IC),
                    0xB7 => Ok(Reg::CC23IC),
                    0xB8 => Ok(Reg::CC24IC),
                    0xB9 => Ok(Reg::CC25IC),
                    0xBA => Ok(Reg::CC26IC),
                    0xBB => Ok(Reg::CC27IC),
                    0xBC => Ok(Reg::CC28IC),
                    0xC2 => Ok(Reg::CC29IC),
                    0xC6 => Ok(Reg::CC30IC),
                    0xCA => Ok(Reg::CC31IC),
                    0x80 => Ok(Reg::DP0L),
                    0x81 => Ok(Reg::DP0H),
                    0x82 => Ok(Reg::DP1L),
                    0x83 => Ok(Reg::DP1H),
                    0xE0 => Ok(Reg::EXICON),
                    0xE1 => Ok(Reg::ODP2),
                    0xE3 => Ok(Reg::ODP3),
                    0xE7 => Ok(Reg::ODP6),
                    0xE9 => Ok(Reg::ODP7),
                    0xEB => Ok(Reg::ODP8),
                    0xE2 => Ok(Reg::PICON),
                    0x1C => Ok(Reg::PP0),
                    0x1D => Ok(Reg::PP1),
                    0x1E => Ok(Reg::PP2),
                    0x1F => Ok(Reg::PP3),
                    0x18 => Ok(Reg::PT0),
                    0x19 => Ok(Reg::PT1),
                    0x1A => Ok(Reg::PT2),
                    0x1B => Ok(Reg::PT3),
                    0xBF => Ok(Reg::PWMIC),
                    0x84 => Ok(Reg::RP0H),
                    0xCE => Ok(Reg::S0TBIC),
                    0x5A => Ok(Reg::SSCBR),
                    0x59 => Ok(Reg::SSCRB),
                    0x58 => Ok(Reg::SSCTB),
                    0x28 => Ok(Reg::T7),
                    0xBD => Ok(Reg::T7IC),
                    0x2A => Ok(Reg::T7REL),
                    0x29 => Ok(Reg::T8),
                    0xBE => Ok(Reg::T8IC),
                    0x2B => Ok(Reg::T8REL),
                    0xC3 => Ok(Reg::XP0IC),
                    0xC7 => Ok(Reg::XP1IC),
                    0xCB => Ok(Reg::XP2IC),
                    0xCF => Ok(Reg::XP3IC),
                    r @ _ => Ok(Reg::ESFR(r)),
                }
            },
            &OperandType::ByteRegister(_) |
            &OperandType::WordRegister(_) => {
                match reg {
                    0xCC => Ok(Reg::ADCIC),
                    0xD0 => Ok(Reg::ADCON),
                    0x50 => Ok(Reg::ADDAT),
                    0x0C => Ok(Reg::ADDRSEL1),
                    0x0D => Ok(Reg::ADDRSEL2),
                    0x0E => Ok(Reg::ADDRSEL3),
                    0x0F => Ok(Reg::ADDRSEL4),
                    0xCD => Ok(Reg::ADEIC),
                    0x86 => Ok(Reg::BUSCON0),
                    0x8A => Ok(Reg::BUSCON1),
                    0x8B => Ok(Reg::BUSCON2),
                    0x8C => Ok(Reg::BUSCON3),
                    0x8D => Ok(Reg::BUSCON4),
                    0x25 => Ok(Reg::CAPREL),
                    0x40 => Ok(Reg::CC0),
                    0xBC => Ok(Reg::CC0IC),
                    0x41 => Ok(Reg::CC1),
                    0xBD => Ok(Reg::CC1IC),
                    0x42 => Ok(Reg::CC2),
                    0xBE => Ok(Reg::CC2IC),
                    0x43 => Ok(Reg::CC3),
                    0xBF => Ok(Reg::CC3IC),
                    0x44 => Ok(Reg::CC4),
                    0xC0 => Ok(Reg::CC4IC),
                    0x45 => Ok(Reg::CC5),
                    0xC1 => Ok(Reg::CC5IC),
                    0x46 => Ok(Reg::CC6),
                    0xC2 => Ok(Reg::CC6IC),
                    0x47 => Ok(Reg::CC7),
                    0xC3 => Ok(Reg::CC7IC),
                    0x48 => Ok(Reg::CC8),
                    0xC4 => Ok(Reg::CC8IC),
                    0x49 => Ok(Reg::CC9),
                    0xC5 => Ok(Reg::CC9IC),
                    0x4A => Ok(Reg::CC10),
                    0xC6 => Ok(Reg::CC10IC),
                    0x4B => Ok(Reg::CC11),
                    0xC7 => Ok(Reg::CC11IC),
                    0x4C => Ok(Reg::CC12),
                    0xC8 => Ok(Reg::CC12IC),
                    0x4D => Ok(Reg::CC13),
                    0xC9 => Ok(Reg::CC13IC),
                    0x4E => Ok(Reg::CC14),
                    0xCA => Ok(Reg::CC14IC),
                    0x4F => Ok(Reg::CC15),
                    0xCB => Ok(Reg::CC15IC),
                    0x30 => Ok(Reg::CC16),
                    0x31 => Ok(Reg::CC17),
                    0x32 => Ok(Reg::CC18),
                    0x33 => Ok(Reg::CC19),
                    0x34 => Ok(Reg::CC20),
                    0x35 => Ok(Reg::CC21),
                    0x36 => Ok(Reg::CC22),
                    0x37 => Ok(Reg::CC23),
                    0x38 => Ok(Reg::CC24),
                    0x39 => Ok(Reg::CC25),
                    0x3A => Ok(Reg::CC26),
                    0x3B => Ok(Reg::CC27),
                    0x3C => Ok(Reg::CC28),
                    0x3D => Ok(Reg::CC29),
                    0x3E => Ok(Reg::CC30),
                    0x3F => Ok(Reg::CC31),
                    0xA9 => Ok(Reg::CCM0),
                    0xAA => Ok(Reg::CCM1),
                    0xAB => Ok(Reg::CCM2),
                    0xAC => Ok(Reg::CCM3),
                    0x91 => Ok(Reg::CCM4),
                    0x92 => Ok(Reg::CCM5),
                    0x93 => Ok(Reg::CCM6),
                    0x94 => Ok(Reg::CCM7),
                    0x08 => Ok(Reg::CP),
                    0xB5 => Ok(Reg::CRIC),
                    0x04 => Ok(Reg::CSP),
                    0xE1 => Ok(Reg::DP2),
                    0xE3 => Ok(Reg::DP3),
                    0xE5 => Ok(Reg::DP4),
                    0xE7 => Ok(Reg::DP6),
                    0xE9 => Ok(Reg::DP7),
                    0xEB => Ok(Reg::DP8),
                    0x00 => Ok(Reg::DPP0),
                    0x01 => Ok(Reg::DPP1),
                    0x02 => Ok(Reg::DPP2),
                    0x03 => Ok(Reg::DPP3),
                    0x87 => Ok(Reg::MDC),
                    0x06 => Ok(Reg::MDH),
                    0x07 => Ok(Reg::MDL),
                    0x8F => Ok(Reg::ONES),
                    0x80 => Ok(Reg::P0L),
                    0x81 => Ok(Reg::P0H),
                    0x82 => Ok(Reg::P1L),
                    0x83 => Ok(Reg::P1H),
                    0xE0 => Ok(Reg::P2),
                    0xE2 => Ok(Reg::P3),
                    0xE4 => Ok(Reg::P4),
                    0xD1 => Ok(Reg::P5),
                    0xE6 => Ok(Reg::P6),
                    0xE8 => Ok(Reg::P7),
                    0xEA => Ok(Reg::P8),
                    0x60 => Ok(Reg::PECC0),
                    0x61 => Ok(Reg::PECC1),
                    0x62 => Ok(Reg::PECC2),
                    0x63 => Ok(Reg::PECC3),
                    0x64 => Ok(Reg::PECC4),
                    0x65 => Ok(Reg::PECC5),
                    0x66 => Ok(Reg::PECC6),
                    0x67 => Ok(Reg::PECC7),
                    0x88 => Ok(Reg::PSW),
                    0x18 => Ok(Reg::PW0),
                    0x19 => Ok(Reg::PW1),
                    0x1A => Ok(Reg::PW2),
                    0x1B => Ok(Reg::PW3),
                    0x98 => Ok(Reg::PWMCON0),
                    0x99 => Ok(Reg::PWMCON1),
                    0x5A => Ok(Reg::S0BG),
                    0xD8 => Ok(Reg::S0CON),
                    0xB8 => Ok(Reg::S0EIC),
                    0x59 => Ok(Reg::S0RBUF),
                    0xB7 => Ok(Reg::S0RIC),
                    0x58 => Ok(Reg::S0TBUF),
                    0xB6 => Ok(Reg::S0TIC),
                    0x09 => Ok(Reg::SP),
                    0xD9 => Ok(Reg::SSCCON),
                    0xBB => Ok(Reg::SSCEIC),
                    0xBA => Ok(Reg::SSCRIC),
                    0xB9 => Ok(Reg::SSCTIC),
                    0x0A => Ok(Reg::STKOV),
                    0x0B => Ok(Reg::STKUN),
                    0x89 => Ok(Reg::SYSCON),
                    0x28 => Ok(Reg::T0),
                    0xA8 => Ok(Reg::T01CON),
                    0xCE => Ok(Reg::T0IC),
                    0x2A => Ok(Reg::T0REL),
                    0x29 => Ok(Reg::T1),
                    0xCF => Ok(Reg::T1IC),
                    0x2B => Ok(Reg::T1REL),
                    0x20 => Ok(Reg::T2),
                    0xA0 => Ok(Reg::T2CON),
                    0xB0 => Ok(Reg::T2IC),
                    0x21 => Ok(Reg::T3),
                    0xA1 => Ok(Reg::T3CON),
                    0xB1 => Ok(Reg::T3IC),
                    0x22 => Ok(Reg::T4),
                    0xA2 => Ok(Reg::T4CON),
                    0xB2 => Ok(Reg::T4IC),
                    0x23 => Ok(Reg::T5),
                    0xA3 => Ok(Reg::T5CON),
                    0xB3 => Ok(Reg::T5IC),
                    0x24 => Ok(Reg::T6),
                    0xA4 => Ok(Reg::T6CON),
                    0xB4 => Ok(Reg::T6IC),
                    0x90 => Ok(Reg::T78CON),
                    0xD6 => Ok(Reg::TFR),
                    0x57 => Ok(Reg::WDT),
                    0xD7 => Ok(Reg::WDTCON),
                    0x8E => Ok(Reg::ZEROS),
                    _ => match reg_type {
                        OperandType::ByteRegister(_) |
                        OperandType::WordRegister(_) => {
                            match reg {
                                0xF0..=0xFF => Reg::from_reg4(reg - 0xF0, reg_type),
                                r @ _ => Ok(Reg::SFR(r)),
                            }
                        },
                        _ => Err(()) // "Invalid SFR register type and short address")
                    }
                }
            },
            _ => Err(())
        }
    }

    pub fn from_phys16(address: u16, reg_type: &OperandType) -> Result<Reg, ()> {
        match reg_type {
            &OperandType::ExtendedRegister => {
                match address {
                    0xFEA0 => Ok(Reg::ADDAT2),
                    0xF160 => Ok(Reg::CC16IC),
                    0xF162 => Ok(Reg::CC17IC),
                    0xF164 => Ok(Reg::CC18IC),
                    0xF166 => Ok(Reg::CC19IC),
                    0xF168 => Ok(Reg::CC20IC),
                    0xF16A => Ok(Reg::CC21IC),
                    0xF16C => Ok(Reg::CC22IC),
                    0xF16E => Ok(Reg::CC23IC),
                    0xF170 => Ok(Reg::CC24IC),
                    0xF172 => Ok(Reg::CC25IC),
                    0xF174 => Ok(Reg::CC26IC),
                    0xF176 => Ok(Reg::CC27IC),
                    0xF178 => Ok(Reg::CC28IC),
                    0xF184 => Ok(Reg::CC29IC),
                    0xF18C => Ok(Reg::CC30IC),
                    0xF194 => Ok(Reg::CC31IC),
                    0xF100 => Ok(Reg::DP0L),
                    0xF102 => Ok(Reg::DP0H),
                    0xF104 => Ok(Reg::DP1L),
                    0xF106 => Ok(Reg::DP1H),
                    0xF1C0 => Ok(Reg::EXICON),
                    0xF1C2 => Ok(Reg::ODP2),
                    0xF1C6 => Ok(Reg::ODP3),
                    0xF1CE => Ok(Reg::ODP6),
                    0xF1D2 => Ok(Reg::ODP7),
                    0xF1D6 => Ok(Reg::ODP8),
                    0xF1C4 => Ok(Reg::PICON),
                    0xF038 => Ok(Reg::PP0),
                    0xF03A => Ok(Reg::PP1),
                    0xF03C => Ok(Reg::PP2),
                    0xF03E => Ok(Reg::PP3),
                    0xF030 => Ok(Reg::PT0),
                    0xF032 => Ok(Reg::PT1),
                    0xF034 => Ok(Reg::PT2),
                    0xF036 => Ok(Reg::PT3),
                    0xF17E => Ok(Reg::PWMIC),
                    0xF108 => Ok(Reg::RP0H),
                    0xF19C => Ok(Reg::S0TBIC),
                    0xF0B4 => Ok(Reg::SSCBR),
                    0xF0B2 => Ok(Reg::SSCRB),
                    0xF0B0 => Ok(Reg::SSCTB),
                    0xF050 => Ok(Reg::T7),
                    0xF17A => Ok(Reg::T7IC),
                    0xF054 => Ok(Reg::T7REL),
                    0xF052 => Ok(Reg::T8),
                    0xF17C => Ok(Reg::T8IC),
                    0xF056 => Ok(Reg::T8REL),
                    0xF186 => Ok(Reg::XP0IC),
                    0xF18E => Ok(Reg::XP1IC),
                    0xF196 => Ok(Reg::XP2IC),
                    0xF19E => Ok(Reg::XP3IC),
                    _ => Err(())
                }
            },
            &OperandType::ByteRegister(_) |
            &OperandType::WordRegister(_) => {
                match address {
                    0xFF98 => Ok(Reg::ADCIC),
                    0xFFA0 => Ok(Reg::ADCON),
                    0xFEA0 => Ok(Reg::ADDAT),
                    0xF0A0 => Ok(Reg::ADDAT2),
                    0xFE18 => Ok(Reg::ADDRSEL1),
                    0xFE1A => Ok(Reg::ADDRSEL2),
                    0xFE1C => Ok(Reg::ADDRSEL3),
                    0xFE1E => Ok(Reg::ADDRSEL4),
                    0xFF9A => Ok(Reg::ADEIC),
                    0xFF0C => Ok(Reg::BUSCON0),
                    0xFF14 => Ok(Reg::BUSCON1),
                    0xFF16 => Ok(Reg::BUSCON2),
                    0xFF18 => Ok(Reg::BUSCON3),
                    0xFF1A => Ok(Reg::BUSCON4),
                    0xEF04 => Ok(Reg::C1BTR),
                    0xEF00 => Ok(Reg::C1CSR),
                    0xEF06 => Ok(Reg::C1GMS),
                    0xEF02 => Ok(Reg::C1IR),
                    0xEF0A => Ok(Reg::C1LGML),
                    0xEF0E => Ok(Reg::C1LMLM),
                    0xEF08 => Ok(Reg::C1UGML),
                    0xEF0C => Ok(Reg::C1UMLM),
                    0xFE4A => Ok(Reg::CAPREL),
                    0xFE80 => Ok(Reg::CC0),
                    0xFF78 => Ok(Reg::CC0IC),
                    0xFFC2 => Ok(Reg::DP2),
                    0xFFC6 => Ok(Reg::DP3),
                    0xFFCA => Ok(Reg::DP4),
                    0xFFCE => Ok(Reg::DP6),
                    0xFFD2 => Ok(Reg::DP7),
                    0xFFD6 => Ok(Reg::DP8),
                    0xFE00 => Ok(Reg::DPP0),
                    0xFE02 => Ok(Reg::DPP1),
                    0xFE04 => Ok(Reg::DPP2),
                    0xFE06 => Ok(Reg::DPP3),
                    0xF1C0 => Ok(Reg::EXICON),
                    0xFF0E => Ok(Reg::MDC),
                    0xFE0C => Ok(Reg::MDH),
                    0xFE0E => Ok(Reg::MDL),
                    0xF1C2 => Ok(Reg::ODP2),
                    0xF1C6 => Ok(Reg::ODP3),
                    0xF1CE => Ok(Reg::ODP6),
                    0xF1D2 => Ok(Reg::ODP7),
                    0xF1D6 => Ok(Reg::ODP8),
                    0xFF1E => Ok(Reg::ONES),
                    0xFF00 => Ok(Reg::P0L),
                    0xFF02 => Ok(Reg::P0H),
                    0xFF04 => Ok(Reg::P1L),
                    0xFF06 => Ok(Reg::P1H),
                    0xFFC0 => Ok(Reg::P2),
                    0xFFC4 => Ok(Reg::P3),
                    0xFFC8 => Ok(Reg::P4),
                    0xFFA2 => Ok(Reg::P5),
                    0xFFCC => Ok(Reg::P6),
                    0xFFD0 => Ok(Reg::P7),
                    0xFFD4 => Ok(Reg::P8),
                    0xFEC0 => Ok(Reg::PECC0),
                    0xFEC2 => Ok(Reg::PECC1),
                    0xFEC4 => Ok(Reg::PECC2),
                    0xFEC6 => Ok(Reg::PECC3),
                    0xFEC8 => Ok(Reg::PECC4),
                    0xFECA => Ok(Reg::PECC5),
                    0xFECC => Ok(Reg::PECC6),
                    0xFECE => Ok(Reg::PECC7),
                    0xF1C4 => Ok(Reg::PICON),
                    0xF038 => Ok(Reg::PP0),
                    0xF03A => Ok(Reg::PP1),
                    0xF03C => Ok(Reg::PP2),
                    0xF03E => Ok(Reg::PP3),
                    0xFF10 => Ok(Reg::PSW),
                    0xF030 => Ok(Reg::PT0),
                    0xF032 => Ok(Reg::PT1),
                    0xF034 => Ok(Reg::PT2),
                    0xF036 => Ok(Reg::PT3),
                    0xFE30 => Ok(Reg::PW0),
                    0xFE32 => Ok(Reg::PW1),
                    0xFE34 => Ok(Reg::PW2),
                    0xFE36 => Ok(Reg::PW3),
                    0xFF30 => Ok(Reg::PWMCON0),
                    0xFF32 => Ok(Reg::PWMCON1),
                    0xF17E => Ok(Reg::PWMIC),
                    0xF108 => Ok(Reg::RP0H),
                    0xFEB4 => Ok(Reg::S0BG),
                    0xFFB0 => Ok(Reg::S0CON),
                    0xFF70 => Ok(Reg::S0EIC),
                    0xFEB2 => Ok(Reg::S0RBUF),
                    0xFF6E => Ok(Reg::S0RIC),
                    0xF19C => Ok(Reg::S0TBIC),
                    0xFEB0 => Ok(Reg::S0TBUF),
                    0xFF6C => Ok(Reg::S0TIC),
                    0xFE12 => Ok(Reg::SP),
                    0xF0B4 => Ok(Reg::SSCBR),
                    0xFFB2 => Ok(Reg::SSCCON),
                    0xFF76 => Ok(Reg::SSCEIC),
                    0xF0B2 => Ok(Reg::SSCRB),
                    0xFF74 => Ok(Reg::SSCRIC),
                    0xF0B0 => Ok(Reg::SSCTB),
                    0xFF72 => Ok(Reg::SSCTIC),
                    0xFE14 => Ok(Reg::STKOV),
                    0xFE16 => Ok(Reg::STKUN),
                    0xFF12 => Ok(Reg::SYSCON),
                    0xFE50 => Ok(Reg::T0),
                    0xFF50 => Ok(Reg::T01CON),
                    0xFF9C => Ok(Reg::T0IC),
                    0xFE54 => Ok(Reg::T0REL),
                    0xFE52 => Ok(Reg::T1),
                    0xFF9E => Ok(Reg::T1IC),
                    0xFE56 => Ok(Reg::T1REL),
                    0xFFAC => Ok(Reg::TFR),
                    0xFEAE => Ok(Reg::WDT),
                    0xFFAE => Ok(Reg::WDTCON),
                    0xF186 => Ok(Reg::XP0IC),
                    0xF18E => Ok(Reg::XP1IC),
                    0xF196 => Ok(Reg::XP2IC),
                    0xF19E => Ok(Reg::XP3IC),
                    0xFF1C => Ok(Reg::ZEROS),
                    _ => Err(())
                }
            },
            _ => Err(())
        }
    }

    pub fn is_word_register(&self) -> bool {
        match *self {
            Reg::RL0 => false,
            Reg::RH0 => false,
            Reg::RL1 => false,
            Reg::RH1 => false,
            Reg::RL2 => false,
            Reg::RH2 => false,
            Reg::RL3 => false,
            Reg::RH3 => false,
            Reg::RL4 => false,
            Reg::RH4 => false,
            Reg::RL5 => false,
            Reg::RH5 => false,
            Reg::RL6 => false,
            Reg::RH6 => false,
            Reg::RL7 => false,
            Reg::RH7 => false,
            _        => true,
        }
    }

    pub fn is_byte_register(&self) -> bool {
        match *self {
            Reg::R0 => false,
            Reg::R1 => false,
            Reg::R2 => false,
            Reg::R3 => false,
            Reg::R4 => false,
            Reg::R5 => false,
            Reg::R6 => false,
            Reg::R7 => false,
            Reg::R8 => false,
            Reg::R9 => false,
            Reg::R10 => false,
            Reg::R12 => false,
            Reg::R13 => false,
            Reg::R14 => false,
            Reg::R15 => false,
            _        => true,
        }
    }

}

impl FromStr for Reg {
    type Err = ();

    fn from_str(s: &str) -> Result<Reg, ()> {
        let mnem = String::from(s).to_uppercase();
        match mnem.as_str() {
            "RL0" => Ok(Reg::RL0),
            "RH0" => Ok(Reg::RH0),
            "RL1" => Ok(Reg::RL1),
            "RH1" => Ok(Reg::RH1),
            "RL2" => Ok(Reg::RL2),
            "RH2" => Ok(Reg::RH2),
            "RL3" => Ok(Reg::RL3),
            "RH3" => Ok(Reg::RH3),
            "RL4" => Ok(Reg::RL4),
            "RH4" => Ok(Reg::RH4),
            "RL5" => Ok(Reg::RL5),
            "RH5" => Ok(Reg::RH5),
            "RL6" => Ok(Reg::RL6),
            "RH6" => Ok(Reg::RH6),
            "RL7" => Ok(Reg::RL7),
            "RH7" => Ok(Reg::RH7),

            "R0" => Ok(Reg::R0),
            "R1" => Ok(Reg::R1),
            "R2" => Ok(Reg::R2),
            "R3" => Ok(Reg::R3),
            "R4" => Ok(Reg::R4),
            "R5" => Ok(Reg::R5),
            "R6" => Ok(Reg::R6),
            "R7" => Ok(Reg::R7),
            "R8" => Ok(Reg::R8),
            "R9" => Ok(Reg::R9),
            "R10" => Ok(Reg::R10),
            "R11" => Ok(Reg::R11),
            "R12" => Ok(Reg::R12),
            "R13" => Ok(Reg::R13),
            "R14" => Ok(Reg::R14),
            "R15" => Ok(Reg::R15),

            "ADCIC"       => Ok(Reg::ADCIC),
            "ADCON"       => Ok(Reg::ADCON),
            "ADDAT"       => Ok(Reg::ADDAT),
            "ADDRSEL1"    => Ok(Reg::ADDRSEL1),
            "ADDRSEL2"    => Ok(Reg::ADDRSEL2),
            "ADDRSEL3"    => Ok(Reg::ADDRSEL3),
            "ADDRSEL4"    => Ok(Reg::ADDRSEL4),
            "ADEIC"       => Ok(Reg::ADEIC),
            "BUSCON0"     => Ok(Reg::BUSCON0),
            "BUSCON1"     => Ok(Reg::BUSCON1),
            "BUSCON2"     => Ok(Reg::BUSCON2),
            "BUSCON3"     => Ok(Reg::BUSCON3),
            "BUSCON4"     => Ok(Reg::BUSCON4),
            "CAPREL"      => Ok(Reg::CAPREL),
            "CC0"         => Ok(Reg::CC0),
            "CC0IC"       => Ok(Reg::CC0IC),
            "CC1"         => Ok(Reg::CC1),
            "CC1IC"       => Ok(Reg::CC1IC),
            "CC2"         => Ok(Reg::CC2),
            "CC2IC"       => Ok(Reg::CC2IC),
            "CC3"         => Ok(Reg::CC3),
            "CC3IC"       => Ok(Reg::CC3IC),
            "CC4"         => Ok(Reg::CC4),
            "CC4IC"       => Ok(Reg::CC4IC),
            "CC5"         => Ok(Reg::CC5),
            "CC5IC"       => Ok(Reg::CC5IC),
            "CC6"         => Ok(Reg::CC6),
            "CC6IC"       => Ok(Reg::CC6IC),
            "CC7"         => Ok(Reg::CC7),
            "CC7IC"       => Ok(Reg::CC7IC),
            "CC8"         => Ok(Reg::CC8),
            "CC8IC"       => Ok(Reg::CC8IC),
            "CC9"         => Ok(Reg::CC9),
            "CC9IC"       => Ok(Reg::CC9IC),
            "CC10"        => Ok(Reg::CC10),
            "CC10IC"      => Ok(Reg::CC10IC),
            "CC11"        => Ok(Reg::CC11),
            "CC11IC"      => Ok(Reg::CC11IC),
            "CC12"        => Ok(Reg::CC12),
            "CC12IC"      => Ok(Reg::CC12IC),
            "CC13"        => Ok(Reg::CC13),
            "CC13IC"      => Ok(Reg::CC13IC),
            "CC14"        => Ok(Reg::CC14),
            "CC14IC"      => Ok(Reg::CC14IC),
            "CC15"        => Ok(Reg::CC15),
            "CC15IC"      => Ok(Reg::CC15IC),
            "CC16"        => Ok(Reg::CC16),
            "CC17"        => Ok(Reg::CC17),
            "CC18"        => Ok(Reg::CC18),
            "CC19"        => Ok(Reg::CC19),
            "CC20"        => Ok(Reg::CC20),
            "CC21"        => Ok(Reg::CC21),
            "CC22"        => Ok(Reg::CC22),
            "CC23"        => Ok(Reg::CC23),
            "CC24"        => Ok(Reg::CC24),
            "CC25"        => Ok(Reg::CC25),
            "CC26"        => Ok(Reg::CC26),
            "CC27"        => Ok(Reg::CC27),
            "CC28"        => Ok(Reg::CC28),
            "CC29"        => Ok(Reg::CC29),
            "CC30"        => Ok(Reg::CC30),
            "CC31"        => Ok(Reg::CC31),
            "CCM0"        => Ok(Reg::CCM0),
            "CCM1"        => Ok(Reg::CCM1),
            "CCM2"        => Ok(Reg::CCM2),
            "CCM3"        => Ok(Reg::CCM3),
            "CCM4"        => Ok(Reg::CCM4),
            "CCM5"        => Ok(Reg::CCM5),
            "CCM6"        => Ok(Reg::CCM6),
            "CCM7"        => Ok(Reg::CCM7),
            "CP"          => Ok(Reg::CP),
            "CRIC"        => Ok(Reg::CRIC),
            "CSP"         => Ok(Reg::CSP),
            "DP2"         => Ok(Reg::DP2),
            "DP3"         => Ok(Reg::DP3),
            "DP4"         => Ok(Reg::DP4),
            "DP6"         => Ok(Reg::DP6),
            "DP7"         => Ok(Reg::DP7),
            "DP8"         => Ok(Reg::DP8),
            "DPP0"        => Ok(Reg::DPP0),
            "DPP1"        => Ok(Reg::DPP1),
            "DPP2"        => Ok(Reg::DPP2),
            "DPP3"        => Ok(Reg::DPP3),
            "MDC"         => Ok(Reg::MDC),
            "MDH"         => Ok(Reg::MDH),
            "MDL"         => Ok(Reg::MDL),
            "ONES"        => Ok(Reg::ONES),
            "P0L"         => Ok(Reg::P0L),
            "P0H"         => Ok(Reg::P0H),
            "P1L"         => Ok(Reg::P1L),
            "P1H"         => Ok(Reg::P1H),
            "P2"          => Ok(Reg::P2),
            "P3"          => Ok(Reg::P3),
            "P4"          => Ok(Reg::P4),
            "P5"          => Ok(Reg::P5),
            "P6"          => Ok(Reg::P6),
            "P7"          => Ok(Reg::P7),
            "P8"          => Ok(Reg::P8),
            "PECC0"       => Ok(Reg::PECC0),
            "PECC1"       => Ok(Reg::PECC1),
            "PECC2"       => Ok(Reg::PECC2),
            "PECC3"       => Ok(Reg::PECC3),
            "PECC4"       => Ok(Reg::PECC4),
            "PECC5"       => Ok(Reg::PECC5),
            "PECC6"       => Ok(Reg::PECC6),
            "PECC7"       => Ok(Reg::PECC7),
            "PSW"         => Ok(Reg::PSW),
            "PW0"         => Ok(Reg::PW0),
            "PW1"         => Ok(Reg::PW1),
            "PW2"         => Ok(Reg::PW2),
            "PW3"         => Ok(Reg::PW3),
            "PWMCON0"     => Ok(Reg::PWMCON0),
            "PWMCON1"     => Ok(Reg::PWMCON1),
            "S0BG"        => Ok(Reg::S0BG),
            "S0CON"       => Ok(Reg::S0CON),
            "S0EIC"       => Ok(Reg::S0EIC),
            "S0RBUF"      => Ok(Reg::S0RBUF),
            "S0RIC"       => Ok(Reg::S0RIC),
            "S0TBUF"      => Ok(Reg::S0TBUF),
            "S0TIC"       => Ok(Reg::S0TIC),
            "SP"          => Ok(Reg::SP),
            "SSCCON"      => Ok(Reg::SSCCON),
            "SSCEIC"      => Ok(Reg::SSCEIC),
            "SSCRIC"      => Ok(Reg::SSCRIC),
            "SSCTIC"      => Ok(Reg::SSCTIC),
            "STKOV"       => Ok(Reg::STKOV),
            "STKUN"       => Ok(Reg::STKUN),
            "SYSCON"      => Ok(Reg::SYSCON),
            "T0"          => Ok(Reg::T0),
            "T01CON"      => Ok(Reg::T01CON),
            "T0IC"        => Ok(Reg::T0IC),
            "T0REL"       => Ok(Reg::T0REL),
            "T1"          => Ok(Reg::T1),
            "T1IC"        => Ok(Reg::T1IC),
            "T1REL"       => Ok(Reg::T1REL),
            "T2"          => Ok(Reg::T2),
            "T2CON"       => Ok(Reg::T2CON),
            "T2IC"        => Ok(Reg::T2IC),
            "T3"          => Ok(Reg::T3),
            "T3CON"       => Ok(Reg::T3CON),
            "T3IC"        => Ok(Reg::T3IC),
            "T4"          => Ok(Reg::T4),
            "T4CON"       => Ok(Reg::T4CON),
            "T4IC"        => Ok(Reg::T4IC),
            "T5"          => Ok(Reg::T5),
            "T5CON"       => Ok(Reg::T5CON),
            "T5IC"        => Ok(Reg::T5IC),
            "T6"          => Ok(Reg::T6),
            "T6CON"       => Ok(Reg::T6CON),
            "T6IC"        => Ok(Reg::T6IC),
            "T78CON"      => Ok(Reg::T78CON),
            "TFR"         => Ok(Reg::TFR),
            "WDT"         => Ok(Reg::WDT),
            "WDTCON"      => Ok(Reg::WDTCON),
            "ZEROS"       => Ok(Reg::ZEROS),

            _ => Err(()),
        }
    }
}

impl fmt::Display for Reg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            // Seriously rust??? This is AWFUL.
            Reg::R0 => write!(f, "r0"),
            Reg::R1 => write!(f, "r1"),
            Reg::R2 => write!(f, "r2"),
            Reg::R3 => write!(f, "r3"),
            Reg::R4 => write!(f, "r4"),
            Reg::R5 => write!(f, "r5"),
            Reg::R6 => write!(f, "r6"),
            Reg::R7 => write!(f, "r7"),
            Reg::R8 => write!(f, "r8"),
            Reg::R9 => write!(f, "r9"),
            Reg::R10 => write!(f, "r10"),
            Reg::R11 => write!(f, "r11"),
            Reg::R12 => write!(f, "r12"),
            Reg::R13 => write!(f, "r13"),
            Reg::R14 => write!(f, "r14"),
            Reg::R15 => write!(f, "r15"),

            Reg::RL0 => write!(f, "rl0"),
            Reg::RH0 => write!(f, "rh0"),
            Reg::RL1 => write!(f, "rl1"),
            Reg::RH1 => write!(f, "rh1"),
            Reg::RL2 => write!(f, "rl2"),
            Reg::RH2 => write!(f, "rh2"),
            Reg::RL3 => write!(f, "rl3"),
            Reg::RH3 => write!(f, "rh3"),
            Reg::RL4 => write!(f, "rl4"),
            Reg::RH4 => write!(f, "rh4"),
            Reg::RL5 => write!(f, "rl5"),
            Reg::RH5 => write!(f, "rh5"),
            Reg::RL6 => write!(f, "rl6"),
            Reg::RH6 => write!(f, "rh6"),
            Reg::RL7 => write!(f, "rl7"),
            Reg::RH7 => write!(f, "rh7"),

            Reg::SFR(r) => write!(f, "{:04X}h", 0xFE00 + (r as u16 * 2)),
            Reg::ESFR(r) => write!(f, "{:04X}h", 0xF000 + (r as u16 * 2)),

            _ => write!(f, "{:?}", self)
        }
    }
}
