/** @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 |