| /*++ |
| |
| Copyright (c) 2013 Intel Corporation. |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions |
| are met: |
| |
| * Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| * Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in |
| the documentation and/or other materials provided with the |
| distribution. |
| * Neither the name of Intel Corporation nor the names of its |
| contributors may be used to endorse or promote products derived |
| from this software without specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| Module Name: |
| |
| Lprint.c |
| |
| Abstract: |
| |
| Serial conole output and string formating. |
| |
| --*/ |
| #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 >> 60) & 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 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 |