/** @file Serial conole output and string formating. Copyright (c) 2013-2015 Intel Corporation. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #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 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 #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