| /** @file | |
| Serial conole output and string formating. | |
| Copyright (c) 2013-2015 Intel Corporation. | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "memory_options.h" | |
| #include "general_definitions.h" | |
| // Resource programmed to PCI bridge, 1MB bound alignment is needed. | |
| // The default value is overwritten by MRC parameter, assuming code | |
| // relocated to eSRAM. | |
| uint32_t UartMmioBase = 0; | |
| // Serial port registers based on SerialPortLib.c | |
| #define R_UART_BAUD_THR 0 | |
| #define R_UART_LSR 20 | |
| #define B_UART_LSR_RXRDY BIT0 | |
| #define B_UART_LSR_TXRDY BIT5 | |
| #define B_UART_LSR_TEMT BIT6 | |
| // Print mask see DPF and D_Xxxx | |
| #define DPF_MASK DpfPrintMask | |
| // Select class of messages enabled for printing | |
| uint32_t DpfPrintMask = | |
| D_ERROR | | |
| D_INFO | | |
| // D_REGRD | | |
| // D_REGWR | | |
| // D_FCALL | | |
| // D_TRN | | |
| 0; | |
| #ifdef NDEBUG | |
| // Don't generate debug code | |
| void dpf( uint32_t mask, char_t* bla, ...) | |
| { | |
| return; | |
| } | |
| uint8_t mgetc(void) | |
| { | |
| return 0; | |
| } | |
| uint8_t mgetch(void) | |
| { | |
| return 0; | |
| } | |
| #else | |
| #ifdef SIM | |
| // Use Vpi console in simulation environment | |
| #include <vpi_user.h> | |
| void dpf( uint32_t mask, char_t* bla, ...) | |
| { | |
| va_list va; | |
| if( 0 == (mask & DPF_MASK)) return; | |
| va_start( va, bla); | |
| vpi_vprintf( bla, va); | |
| va_end(va); | |
| } | |
| #else | |
| #ifdef EMU | |
| // Use standard console in windows environment | |
| #include <stdio.h> | |
| #endif | |
| // Read character from serial port | |
| uint8_t mgetc(void) | |
| { | |
| #ifdef EMU | |
| // Emulation in Windows environment uses console | |
| getchar(); | |
| #else | |
| uint8_t c; | |
| while ((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) == 0); | |
| c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR); | |
| return c; | |
| #endif | |
| } | |
| uint8_t mgetch(void) | |
| { | |
| #ifdef EMU | |
| return 0; | |
| #else | |
| uint8_t c = 0; | |
| if((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) != 0) | |
| { | |
| c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR); | |
| } | |
| return c; | |
| #endif | |
| } | |
| // Print single character | |
| static void printc( | |
| uint8_t c) | |
| { | |
| #ifdef EMU | |
| // Emulation in Windows environment uses console output | |
| putchar(c); | |
| #else | |
| // | |
| // Use MMIO access to serial port on PCI | |
| // while( 0 == (0x20 & inp(0x3f8 + 5))); | |
| // outp(0x3f8 + 0, c); | |
| // | |
| while (0 | |
| == (B_UART_LSR_TEMT & *((volatile uint8_t*) (UartMmioBase + R_UART_LSR)))) | |
| ; | |
| *((volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR)) = c; | |
| #endif | |
| } | |
| // Print 0 terminated string on serial console | |
| static void printstr( | |
| char_t *str) | |
| { | |
| while (*str) | |
| { | |
| printc(*str++); | |
| } | |
| } | |
| // Print 64bit number as hex string on serial console | |
| // the width parameters allows skipping leading zeros | |
| static void printhexx( | |
| uint64_t val, | |
| uint32_t width) | |
| { | |
| uint32_t i; | |
| uint8_t c; | |
| uint8_t empty = 1; | |
| // 64bit number has 16 characters in hex representation | |
| for (i = 16; i > 0; i--) | |
| { | |
| c = *(((uint8_t *)&val) + ((i - 1) >> 1)); | |
| if (((i - 1) & 1) != 0) | |
| c = c >> 4; | |
| c = c & 0x0F; | |
| if (c > 9) | |
| c += 'A' - 10; | |
| else | |
| c += '0'; | |
| if (c != '0') | |
| { | |
| // end of leading zeros | |
| empty = 0; | |
| } | |
| // don't print leading zero | |
| if (!empty || i <= width) | |
| { | |
| printc(c); | |
| } | |
| } | |
| } | |
| // Print 32bit number as hex string on serial console | |
| // the width parameters allows skipping leading zeros | |
| static void printhex( | |
| uint32_t val, | |
| uint32_t width) | |
| { | |
| uint32_t i; | |
| uint8_t c; | |
| uint8_t empty = 1; | |
| // 32bit number has 8 characters in hex representation | |
| for (i = 8; i > 0; i--) | |
| { | |
| c = (uint8_t) ((val >> 28) & 0x0F); | |
| if (c > 9) | |
| c += 'A' - 10; | |
| else | |
| c += '0'; | |
| val = val << 4; | |
| if (c != '0') | |
| { | |
| // end of leading zeros | |
| empty = 0; | |
| } | |
| // don't print leading zero | |
| if (!empty || i <= width) | |
| { | |
| printc(c); | |
| } | |
| } | |
| } | |
| // Print 32bit number as decimal string on serial console | |
| // the width parameters allows skipping leading zeros | |
| static void printdec( | |
| uint32_t val, | |
| uint32_t width) | |
| { | |
| uint32_t i; | |
| uint8_t c = 0; | |
| uint8_t empty = 1; | |
| // Ten digits is enough for 32bit number in decimal | |
| uint8_t buf[10]; | |
| for (i = 0; i < sizeof(buf); i++) | |
| { | |
| c = (uint8_t) (val % 10); | |
| buf[i] = c + '0'; | |
| val = val / 10; | |
| } | |
| while (i > 0) | |
| { | |
| c = buf[--i]; | |
| if (c != '0') | |
| { | |
| // end of leading zeros | |
| empty = 0; | |
| } | |
| // don't print leading zero | |
| if (!empty || i < width) | |
| { | |
| printc(c); | |
| } | |
| } | |
| } | |
| // Consume numeric substring leading the given string | |
| // Return pointer to the first non-numeric character | |
| // Buffer reference by width is updated with number | |
| // converted from the numeric substring. | |
| static char_t *getwidth( | |
| char_t *bla, | |
| uint32_t *width) | |
| { | |
| uint32_t val = 0; | |
| while (*bla >= '0' && *bla <= '9') | |
| { | |
| val = val * 10 + *bla - '0'; | |
| bla += 1; | |
| } | |
| if (val > 0) | |
| { | |
| *width = val; | |
| } | |
| return bla; | |
| } | |
| // Consume print format designator from the head of given string | |
| // Return pointer to first character after format designator | |
| // input fmt | |
| // ----- --- | |
| // s -> s | |
| // d -> d | |
| // X -> X | |
| // llX -> L | |
| static char_t *getformat( | |
| char_t *bla, | |
| uint8_t *fmt) | |
| { | |
| if (bla[0] == 's') | |
| { | |
| bla += 1; | |
| *fmt = 's'; | |
| } | |
| else if (bla[0] == 'd') | |
| { | |
| bla += 1; | |
| *fmt = 'd'; | |
| } | |
| else if (bla[0] == 'X' || bla[0] == 'x') | |
| { | |
| bla += 1; | |
| *fmt = 'X'; | |
| } | |
| else if (bla[0] == 'l' && bla[1] == 'l' && bla[2] == 'X') | |
| { | |
| bla += 3; | |
| *fmt = 'L'; | |
| } | |
| return bla; | |
| } | |
| // Simplified implementation of standard printf function | |
| // The output is directed to serial console. Only selected | |
| // class of messages is printed (mask has to match DpfPrintMask) | |
| // Supported print formats: %[n]s,%[n]d,%[n]X,,%[n]llX | |
| // The width is ignored for %s format. | |
| void dpf( | |
| uint32_t mask, | |
| char_t* bla, | |
| ...) | |
| { | |
| uint32_t* arg = (uint32_t*) (&bla + 1); | |
| // Check UART MMIO base configured | |
| if (0 == UartMmioBase) | |
| return; | |
| // Check event not masked | |
| if (0 == (mask & DPF_MASK)) | |
| return; | |
| for (;;) | |
| { | |
| uint8_t x = *bla++; | |
| if (x == 0) | |
| break; | |
| if (x == '\n') | |
| { | |
| printc('\r'); | |
| printc('\n'); | |
| } | |
| else if (x == '%') | |
| { | |
| uint8_t fmt = 0; | |
| uint32_t width = 1; | |
| bla = getwidth(bla, &width); | |
| bla = getformat(bla, &fmt); | |
| // Print value | |
| if (fmt == 'd') | |
| { | |
| printdec(*arg, width); | |
| arg += 1; | |
| } | |
| else if (fmt == 'X') | |
| { | |
| printhex(*arg, width); | |
| arg += 1; | |
| } | |
| else if (fmt == 'L') | |
| { | |
| printhexx(*(uint64_t*) arg, width); | |
| arg += 2; | |
| } | |
| else if (fmt == 's') | |
| { | |
| printstr(*(char**) arg); | |
| arg += 1; | |
| } | |
| } | |
| else | |
| { | |
| printc(x); | |
| } | |
| } | |
| } | |
| #endif //SIM | |
| #endif //NDEBUG |