Debugging library

MDebugger.cpp

Committer:
Gofs
Date:
2014-06-25
Revision:
0:57b729dee92c
Child:
1:05bd8eb25467

File content as of revision 0:57b729dee92c:

#include <MDebugger.h>
#include <stdio.h>
#include <stdarg.h>

#if MDEBUGGER_CIRCULAR_BUFFER_SIZE_IN_BYTES > 0
static unsigned char MDEBUGGER_CIRCULAR_BUFFER[MDEBUGGER_NUMBER_OF_ADDRESS_CHANNELS][MDEBUGGER_CIRCULAR_BUFFER_SIZE_IN_BYTES] = { 0 };
static uint32_t MDEBUGGER_CIRCULAR_BUFFER_HEAD[MDEBUGGER_NUMBER_OF_ADDRESS_CHANNELS]    = { 0 };
static uint32_t MDEBUGGER_CIRCULAR_BUFFER_TAIL[MDEBUGGER_NUMBER_OF_ADDRESS_CHANNELS]    = { 0 };
static uint32_t MDEBUGGER_CIRCULAR_BUFFER_IS_FULL[MDEBUGGER_NUMBER_OF_ADDRESS_CHANNELS] = { 0 };
#endif

#define ACTLR_REGISTER_VALUE                    (*((uint32_t*)0xE000E008))
#define SYSTICK_REGISTER_VALUE                  (*((uint32_t*)0xE000E010))
#define SYSTICK_RELOAD_VALUE_REGISTER_VALUE     (*((uint32_t*)0xE000E014))
#define SYSTICK_CURRENT_VALUE_REGISTER_VALUE    (*((uint32_t*)0xE000E018))
#define SYSTICK_CALIBRATION_REGISTER_VALUE      (*((uint32_t*)0xE000E01C))

#define SETENA0_REGISTER_VALUE                              (*((uint32_t*)0xE000E200))
#define SETENA1_REGISTER_VALUE                              (*((uint32_t*)0xE000E204))
#define SETENA2_REGISTER_VALUE                              (*((uint32_t*)0xE000E208))
#define SETENA3_REGISTER_VALUE                              (*((uint32_t*)0xE000E20C))
#define SETENA4_REGISTER_VALUE                              (*((uint32_t*)0xE000E210))
#define SETENA5_REGISTER_VALUE                              (*((uint32_t*)0xE000E214))
#define SETENA6_REGISTER_VALUE                              (*((uint32_t*)0xE000E218))
#define SETENA7_REGISTER_VALUE                              (*((uint32_t*)0xE000E21C))

#define CPUID_REGISTER_VALUE                                    (*((uint32_t*)0xE000ED00))
#define ICSR_REGISTER_VALUE                                     (*((uint32_t*)0xE000ED04))
#define VTOR_REGISTER_VALUE                                     (*((uint32_t*)0xE000ED08))
#define AIRCR_REGISTER_VALUE                                    (*((uint32_t*)0xE000ED0C))
#define SCR_REGISTER_VALUE                                      (*((uint32_t*)0xE000ED10))
#define CCR_REGISTER_VALUE                                      (*((uint32_t*)0xE000ED14))
#define SHPR1_REGISTER_VALUE                                    (*((uint32_t*)0xE000ED18))
#define SHPR2_REGISTER_VALUE                                    (*((uint32_t*)0xE000ED1C))
#define SHPR3_REGISTER_VALUE                                    (*((uint32_t*)0xE000ED20))
#define SHCRS_REGISTER_VALUE                                    (*((uint32_t*)0xE000ED24))
#define CFSR_REGISTER_VALUE                                     (*((uint32_t*)0xE000ED28))
#define HFSR_REGISTER_VALUE                                     (*((uint32_t*)0xE000ED2C))
#define MMAR_REGISTER_VALUE                                     (*((uint32_t*)0xE000ED34))
#define BFAR_REGISTER_VALUE                                     (*((uint32_t*)0xE000ED38))
#define AFSR_REGISTER_VALUE                                     (*((uint32_t*)0xE000ED3C))

#define MMU_TYPE_REGISTER_VALUE         (*((uint32_t*)0xE000ED90))
#define MMU_CONTROL_REGISTER_VALUE      (*((uint32_t*)0xE000ED94))
#define MMU_RBASR_REGISTER_VALUE        (*((uint32_t*)0xE000ED9C))


void mdebug_flush(uint32_t channel)
{
    #if MDEBUGGER_CIRCULAR_BUFFER_SIZE_IN_BYTES > 0
    if (mdebug_output_buffer_is_empty(channel)) {
        return;
    }   
    
        do {
            mdebug_putc(MDEBUGGER_CIRCULAR_BUFFER[channel][MDEBUGGER_CIRCULAR_BUFFER_TAIL[channel]], channel);
            
            if (++MDEBUGGER_CIRCULAR_BUFFER_TAIL[channel] == MDEBUGGER_CIRCULAR_BUFFER_SIZE_IN_BYTES)       {
                MDEBUGGER_CIRCULAR_BUFFER_TAIL[channel] = 0;
            } 
        } while (MDEBUGGER_CIRCULAR_BUFFER_HEAD[channel] != MDEBUGGER_CIRCULAR_BUFFER_TAIL[channel]);
        
        MDEBUGGER_CIRCULAR_BUFFER_IS_FULL[channel] = 0;
    #endif
}

void mdebug_write(unsigned char *in_buffer, uint32_t in_buffer_size, uint32_t channel)
{
    uint32_t index;
    
#if MDEBUGGER_CIRCULAR_BUFFER_SIZE_IN_BYTES == 0    
    for (index = 0; index < in_buffer_size; ++index)    {
        mdebug_putc(in_buffer[index], channel);
    }
#else
    
    for (index = 0; index < in_buffer_size; ++index)    {
        MDEBUGGER_CIRCULAR_BUFFER[channel][MDEBUGGER_CIRCULAR_BUFFER_HEAD[channel]] = in_buffer[index];
        
        if (++MDEBUGGER_CIRCULAR_BUFFER_HEAD[channel] == MDEBUGGER_CIRCULAR_BUFFER_SIZE_IN_BYTES)       {
            MDEBUGGER_CIRCULAR_BUFFER_HEAD[channel] = 0;
        }
        
        if (MDEBUGGER_CIRCULAR_BUFFER_HEAD[channel] == MDEBUGGER_CIRCULAR_BUFFER_TAIL[channel])     {
            MDEBUGGER_CIRCULAR_BUFFER_IS_FULL[channel] = 1;
            mdebug_flush(channel);
        }
    }
#endif
}



void mdebug_printf(uint32_t channel, const char *formatting_string, ...)
{
    va_list arg;
    unsigned char buffer[128];
    uint32_t length;    
    
    va_start(arg, formatting_string);
    length = vsprintf((char*)buffer, formatting_string, arg);
    va_end(arg);
    
    mdebug_write(buffer, length, channel);
}

void mdebug_write_unbuffered(unsigned char *in_buffer, uint32_t in_buffer_size, uint32_t channel)
{
    uint32_t index;
    
    for (index = 0; index < in_buffer_size; ++index)    {
        mdebug_putc(in_buffer[index], channel);
    }
}



void mdebug_printf_unbuffered(uint32_t channel, const char *formatting_string, ...)
{
    va_list arg;        
    unsigned char buffer[256];
    uint32_t length;    
    
    va_start(arg, formatting_string);
    length = vsprintf((char*)buffer, formatting_string, arg);
    va_end(arg);
    
    mdebug_write_unbuffered((unsigned char*)buffer, length, channel);
}

uint32_t mdebug_output_bufer_used_space(uint32_t channel)
{
    #if MDEBUGGER_CIRCULAR_BUFFER_SIZE_IN_BYTES > 0
        if (MDEBUGGER_CIRCULAR_BUFFER_HEAD[channel] >= MDEBUGGER_CIRCULAR_BUFFER_TAIL[channel])     {
            return MDEBUGGER_CIRCULAR_BUFFER_HEAD[channel] - MDEBUGGER_CIRCULAR_BUFFER_TAIL[channel];
        }
        else        {
            return MDEBUGGER_CIRCULAR_BUFFER_SIZE_IN_BYTES - MDEBUGGER_CIRCULAR_BUFFER_TAIL[channel] + MDEBUGGER_CIRCULAR_BUFFER_HEAD[channel];
        }
    #else
        reuturn 0;
    #endif
}

uint32_t mdebug_output_buffer_free_space(uint32_t channel)
{
    #if MDEBUGGER_CIRCULAR_BUFFER_SIZE_IN_BYTES > 0
        return MDEBUGGER_CIRCULAR_BUFFER_SIZE_IN_BYTES - mdebug_output_bufer_used_space(channel);
    #else
        reuturn 0;
    #endif
}

uint32_t mdebug_output_buffer_is_empty(uint32_t channel)
{
    if (MDEBUGGER_CIRCULAR_BUFFER_IS_FULL[channel])
    {
        return 0;
    }
    else
    {
        return (MDEBUGGER_CIRCULAR_BUFFER_HEAD[channel] == MDEBUGGER_CIRCULAR_BUFFER_TAIL[channel]);
    }
}



void mdebug_print_system_info()
{
    uint32_t ControlRegister    = __get_CONTROL();
    uint32_t MSP                            = __get_MSP();
    uint32_t PSP;
    uint32_t IPSR;
    uint32_t PRIMASK;
    uint32_t BASEPRI;
    uint32_t FAULTMASK;  
    
    
    switch (ControlRegister & 0x00000003)
    {
        case 0:     // Privileged mode, main stack is used
            PSP = __get_PSP();
            break;
        
        case 2:     // Privileged mode, alternate stack is used
            PSP = __get_PSP();
            break;
        
        default: // could not happen
            break;
    }
    
    IPSR            = __get_IPSR() & 0x000001FF;
    PRIMASK     = __get_PRIMASK();// & 0x00000001;
    BASEPRI     = __get_BASEPRI(); //& 0x000000FF;
    FAULTMASK   = __get_FAULTMASK();// & 0x00000001;
    
    mdebug_printf_unbuffered(0, "\r\n\r\n====================");    
    mdebug_printf_unbuffered(0, "\r\nCONTROL:\t\t0x%08X", ControlRegister);
    
    if (ControlRegister & (1 << 0))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* User mode.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Privileged mode.");
    }
    
    if (ControlRegister & (1 << 1))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Alternate stack is used.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Main stack is used.");
    }
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nIPSR:\t\t\t0x%08X\r\n\t* Context: ", IPSR);
    
    if (IPSR > 16)
    {
        mdebug_printf_unbuffered(0, "interrupt mode. IRQ no %d.", IPSR - 16);
    }
    else
    {
        switch (IPSR)
        {
            case 0:
                mdebug_printf_unbuffered(0, "thread mode.");
                break;
            
            case 2:
                mdebug_printf_unbuffered(0, "NMI.");
                break;
            
            case 3:
                mdebug_printf_unbuffered(0, "hard hault.");
                break;
        
            case 4:
                mdebug_printf_unbuffered(0, "mem manage.");
                break;
            
            case 5:
                mdebug_printf_unbuffered(0, "bus bault.");
                break;
            
            case 6:
                mdebug_printf_unbuffered(0, "usage uault.");
                break;
            
            case 11:
                mdebug_printf_unbuffered(0, "SVCall.");
                break;
            
            case 14:
                mdebug_printf_unbuffered(0, "PendSV.");
                break;
            
            case 15:
                mdebug_printf_unbuffered(0, "SysTick.");
                break;
            
            default:
                mdebug_printf_unbuffered(0, "other. Number %d.", IPSR);
                break;
        }
    }
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nSYSTICK:\t\t\t0x%08X", SYSTICK_REGISTER_VALUE);
    
    if (SYSTICK_REGISTER_VALUE & (1 << 0))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* SysTick is enabled.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* SysTick is disabled.");
    }
    
    if (SYSTICK_REGISTER_VALUE & (1 << 1))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* SysTick interrupt enabled.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* SysTick interrupt disabled.");
    }
    
    if (SYSTICK_REGISTER_VALUE & (1 << 2))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* SysTick uses core clock.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* SysTick uses external clock.");
    }
    
    if (SYSTICK_REGISTER_VALUE & (1 << 16))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* SysTick COUNTFLAG is set.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* SysTick COUNTFLAG is not set.");
    }
    
    mdebug_printf_unbuffered(0, "\r\n\t* SysTick reload register value = %d", SYSTICK_RELOAD_VALUE_REGISTER_VALUE);
    mdebug_printf_unbuffered(0, "\r\n\t* SysTick register current value = %d", SYSTICK_CURRENT_VALUE_REGISTER_VALUE);
    mdebug_printf_unbuffered(0, "\r\n\t* SysTick calibration register value = %d", SYSTICK_CALIBRATION_REGISTER_VALUE);
    
    
    mdebug_printf_unbuffered(0, "\r\n====================");    
    
    switch (ControlRegister & 0x00000003)
    {       
        case 0:     // Privileged mode, main stack is used
        case 2:     // Privileged mode, alternate stack is used
            mdebug_printf_unbuffered(0, "\r\nPSP:\t\t\t0x%08X\tProcess Stack Pointer", PSP); 
        
        case 1:     // User mode, main stack is used
            mdebug_printf_unbuffered(0, "\r\nMSP:\t\t\t0x%08X\tMain Stack Pointer", MSP);
            break;
        
        default: // could not happen
            break;
    }
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nACTLR:\t\t\t0x%08X\tAuxiliary Control Register", ACTLR_REGISTER_VALUE);    
    mdebug_printf_unbuffered(0, "\r\n\t* IT folding is %s", (ACTLR_REGISTER_VALUE & 0x4) == 0 ? "enabled." : "disabled.");
    mdebug_printf_unbuffered(0, "\r\n\t* Write buffer is %s", (ACTLR_REGISTER_VALUE & 0x2) == 0 ? "enabled." : "disabled.");
    mdebug_printf_unbuffered(0, "\r\n\t* LDM and STM interruption is %s", (ACTLR_REGISTER_VALUE & 0x1) == 0 ? "enabled." : "disabled.");
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nCPUID:\t\t\t0x%08X", CPUID_REGISTER_VALUE);
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nICSR:\t\t\t0x%08X\tInterrupt Control and State Register", ICSR_REGISTER_VALUE);
    
    if (ICSR_REGISTER_VALUE & 0x80000000)
    {
        mdebug_printf_unbuffered(0, "\r\n\t* NMI is pending.");     
    }
    
    if (ICSR_REGISTER_VALUE & (1 << 28))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* PendSV is pending.");      
    }
    
    if (ICSR_REGISTER_VALUE & (1 << 26))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* SysTick is pending.");     
    }
    
    
    mdebug_printf_unbuffered(0, "\r\n\t* Highest priority pending enabled exception: ");
    
    if (ICSR_REGISTER_VALUE & 0x0003F000)
    {
        mdebug_printf_unbuffered(0, "%d", (ICSR_REGISTER_VALUE & 0x0003F000) >> 12);
    }
    else
    {
        mdebug_printf_unbuffered(0, "no pending exceptions.");
    }
    
    if (ICSR_REGISTER_VALUE & (1 << 11))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* There are no preempted active exceptions to execute.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* There are preempted active exceptions to execute.");
    }
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nVTOR:\t\t\t0x%08X\tVector Table Offset Register", VTOR_REGISTER_VALUE);
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nAIRCR:\t\t\t0x%08X\tApplication Interrupt and Reset Control Register", AIRCR_REGISTER_VALUE);
    
    if (AIRCR_REGISTER_VALUE & (1 << 15))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Endianness: big-endian.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Endianness: little-endian.");
    }
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nSCR:\t\t\t0x%08X\tSystem Control Register", SCR_REGISTER_VALUE);
    
    if (SCR_REGISTER_VALUE & (1 << 1))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Sleep-on-exit is ON.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Sleep-on-exit is OFF.");
    }
    
    if (SCR_REGISTER_VALUE & (1 << 2))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Processor uses deep sleep mode.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Processor uses sleep mode.");
    }
    
    if (SCR_REGISTER_VALUE & (1 << 4))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Disabled interrupts can wake up the processor.");
    }
    else
    {
        mdebug_printf_unbuffered(0, ",\r\n\t* Disabled interrupts cannot wake up the processor.");
    }   
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nCCR:\t\t\t0x%08X\tConfiguration and Control Register", CCR_REGISTER_VALUE);
    
    if (CCR_REGISTER_VALUE & (1 << 0))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* EXC_RETURN active.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* EXC_RETURN inactive.");
    }   
    
    if (CCR_REGISTER_VALUE & (1 << 1))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Access to STIR in thread mode is enabled.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Access to STIR in thread mode is disabled.");
    }   
    
    if (CCR_REGISTER_VALUE & (1 << 3))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Unaligned access generates UsageFault.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Unaligned access doesn't generate UsageFault.");
    }   
    
    if (CCR_REGISTER_VALUE & (1 << 4))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Div by 0 generates faulting or halting.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Div by 0 returns 0.");
    }   
    
    if (CCR_REGISTER_VALUE & (1 << 8))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Priority -1 and -2 handlers ignore data bus faults caused by load and store instructions.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Data bus faults caused by load and store instructions cause a lock-up.");
    }   
    
    if (CCR_REGISTER_VALUE & (1 << 9))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Stack alignment on exception entry is 8-byte aligned.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Stack alignment on exception entry is 4-byte aligned.");
    }   
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nSHPR1:\t\t\t0x%08X\tSystem Handler Priority Register 1", SHPR1_REGISTER_VALUE);
    mdebug_printf_unbuffered(0, "\r\n\t* MemManage pio = %d.\r\n\t* BusFault prio = %d.\r\n\t* UsageFault prio = %d.", 
                                                        SHPR1_REGISTER_VALUE & 0x000000FF,
                                                        (SHPR1_REGISTER_VALUE & 0x0000FF00) >> 8,
                                                        (SHPR1_REGISTER_VALUE & 0x00FF0000) >> 16);
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nSHPR2:\t\t\t0x%08X\tSystem Handler Priority Register 2", SHPR2_REGISTER_VALUE);
    mdebug_printf_unbuffered(0, "\r\n\t* SVCall prio = %d.", (SHPR2_REGISTER_VALUE & 0xFF000000) >> 24);
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nSHPR3:\t\t\t0x%08X\tSystem Handler Priority Register 3", SHPR3_REGISTER_VALUE);
    mdebug_printf_unbuffered(0, "\r\n\t* PendSV  prio = %d.\r\n\t* SysTick  prio = %d.", (SHPR3_REGISTER_VALUE & 0x00FF0000) >> 16, (SHPR3_REGISTER_VALUE & 0xFF000000) >> 24);
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nSHCRS:\t\t\t0x%08X\tSystem Handler Control and State Register", SHCRS_REGISTER_VALUE);
    
    if (SHCRS_REGISTER_VALUE & 0x00000D8B)
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Active exceptions:");
        
        if (SHCRS_REGISTER_VALUE & (1 << 0))
        {
            mdebug_printf_unbuffered(0, "\r\n\t\t* MemManage.");
        }
        
        if (SHCRS_REGISTER_VALUE & (1 << 1))
        {
            mdebug_printf_unbuffered(0, "\r\n\t\t* BusFault.");
        }
        
        if (SHCRS_REGISTER_VALUE & (1 << 3))
        {
            mdebug_printf_unbuffered(0, "\r\n\t\t* UsageFault.");
        }
        
        if (SHCRS_REGISTER_VALUE & (1 << 7))
        {
            mdebug_printf_unbuffered(0, "\r\n\t\t* SVCall.");
        }
        
        if (SHCRS_REGISTER_VALUE & (1 << 10))
        {
            mdebug_printf_unbuffered(0, "\r\n\t\t* PendSV.");
        }
        
        if (SHCRS_REGISTER_VALUE & (1 << 11))
        {
            mdebug_printf_unbuffered(0, "\r\n\t\t* SysTick.");
        }
    }
    
    if (SHCRS_REGISTER_VALUE & 0x0000F000)
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Pending exceptions:");
        
        if (SHCRS_REGISTER_VALUE & (1 << 12))
        {
            mdebug_printf_unbuffered(0, "\r\n\t\t* UsageFault.");
        }
        
        if (SHCRS_REGISTER_VALUE & (1 << 13))
        {
            mdebug_printf_unbuffered(0, "\r\n\t\t* MemManage.");
        }
        
        if (SHCRS_REGISTER_VALUE & (1 << 14))
        {
            mdebug_printf_unbuffered(0, "\r\n\t\t* BusFault.");
        }
        
        if (SHCRS_REGISTER_VALUE & (1 << 15))
        {
            mdebug_printf_unbuffered(0, "\r\n\t\t* SVCall.");
        }
    }
    
    if (SHCRS_REGISTER_VALUE & 0x00070000)
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Enabled exceptions: ");
        
        if (SHCRS_REGISTER_VALUE & (1 << 16))
        {
            mdebug_printf_unbuffered(0, "\r\n\t\t* MemManage.");
        }
        
        if (SHCRS_REGISTER_VALUE & (1 << 17))
        {
            mdebug_printf_unbuffered(0, "\r\n\t\t* BusFault.");
        }
        
        if (SHCRS_REGISTER_VALUE & (1 << 18))
        {
            mdebug_printf_unbuffered(0, "\r\n\t\t* UsageFault.");
        }
    }
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nCFSR:\t\t\t0x%08X\tConfigurable Fault Status Register", CFSR_REGISTER_VALUE);
    
    if (CFSR_REGISTER_VALUE & (1 << 0))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* The processor attempted an instruction fetch from a location that does not permit execution.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 1))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* The processor attempted a load or store at a location that does not permit the operation.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 3))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Unstack for an exception return has caused one or more access violations.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 4))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Stacking for an exception entry has caused one or more access violations.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 7))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* MMAR holds a valid fault address.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* MMAR doesn't hold a valid fault address.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 8))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Instruction bus error.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 9))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* A data bus error has occurred, and the PC value stacked for the exception return points to the instruction that caused the fault.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 10))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* A data bus error has occurred, but the return address in the stack frame is not related to the instruction that caused the error.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 11))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Unstack for an exception return has caused one or more BusFaults.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 12))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Stacking for an exception entry has caused one or more BusFaults.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 15))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* BFAR holds a valid fault address.");
    }
    else
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Value in BFAR is not a valid fault address.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 16))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* The processor has attempted to execute an undefined instruction.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 17))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* The processor has attempted to execute an instruction that makes illegal use of the EPSR.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 18))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* The processor has attempted an illegal load of EXC_RETURN to the PC, as a result of an invalid context, or an invalid EXC_RETURN value.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 19))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* The processor has attempted to access a coprocessor.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 24))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* The processor has made an unaligned memory access.");
    }
    
    if (CFSR_REGISTER_VALUE & (1 << 25))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* The processor has executed an SDIV or UDIV instruction with a divisor of 0.");
    }
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nHFSR:\t\t\t0x%08X\tHardFault Status Register", HFSR_REGISTER_VALUE);
    
    if (HFSR_REGISTER_VALUE & (1 << 1))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* BusFault on vector table read.");
    }
    
    if (HFSR_REGISTER_VALUE & (1 << 30))
    {
        mdebug_printf_unbuffered(0, "\r\n\t* Forced HardFault.");
    }
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nMMAR:\t\t\t0x%08X\tMemManage Fault Address Register", MMAR_REGISTER_VALUE);
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nBFAR:\t\t\t0x%08X\tBusFault Address Register", BFAR_REGISTER_VALUE);
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nAFSR:\t\t\t0x%08X\tAuxiliary Fault Status Register", AFSR_REGISTER_VALUE);    
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nPRIMASK:\t\t0x%08X", PRIMASK & 0x00000001);
    mdebug_printf_unbuffered(0, "\r\nFAULTMASK:\t\t0x%08X", FAULTMASK & 0x00000001);
    mdebug_printf_unbuffered(0, "\r\nBASEPRI:\t\t0x%08X", BASEPRI & 0x000000FF);
    
    mdebug_printf_unbuffered(0, "\r\n====================");
    mdebug_printf_unbuffered(0, "\r\nMMU Type Register:\t\t0x%08X", MMU_TYPE_REGISTER_VALUE);
    mdebug_printf_unbuffered(0, "\r\nMMU Control Register:\t\t0x%08X", MMU_CONTROL_REGISTER_VALUE);
    mdebug_printf_unbuffered(0, "\r\nMMU Region Base Address Register:\t\t0x%08X", MMU_RBASR_REGISTER_VALUE);
    mdebug_printf_unbuffered(0, "\r\n\t* Number of regions supported by MMU: %d.", (MMU_TYPE_REGISTER_VALUE & 0x0000FF00) >> 8);
    mdebug_printf_unbuffered(0, "\r\n\t* MPU is %s.", (MMU_CONTROL_REGISTER_VALUE & (1 << 0)) == 0 ? "disabled" : "enabled");
    mdebug_printf_unbuffered(0, "\r\n\t* MPU is %s during the hard fault and NMI handlers.", (MMU_CONTROL_REGISTER_VALUE & (1 << 1)) == 0 ? "disabled" : "enabled");
    mdebug_printf_unbuffered(0, "\r\n\t* Privileged Default memory map is %s.", (MMU_CONTROL_REGISTER_VALUE & (1 << 2)) == 0 ? "disabled" : "enabled");

    
    mdebug_printf_unbuffered(0, "\r\n====================");
    
#if defined(__ARMCC_VERSION)
    mdebug_printf_unbuffered(0, "\r\n__ARMCC_VERSION\t\t%u", __ARMCC_VERSION);
#endif
    
#if defined(__ARMCLIB_VERSION)
    mdebug_printf_unbuffered(0, "\r\n__ARMCLIB_VERSION\t%u", __ARMCLIB_VERSION);
#endif
}