1/** @file 2Serial conole output and string formating. 3 4Copyright (c) 2013-2015 Intel Corporation. 5 6This program and the accompanying materials 7are licensed and made available under the terms and conditions of the BSD License 8which accompanies this distribution. The full text of the license may be found at 9http://opensource.org/licenses/bsd-license.php 10 11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14**/ 15#include "memory_options.h" 16#include "general_definitions.h" 17 18// Resource programmed to PCI bridge, 1MB bound alignment is needed. 19// The default value is overwritten by MRC parameter, assuming code 20// relocated to eSRAM. 21uint32_t UartMmioBase = 0; 22 23// Serial port registers based on SerialPortLib.c 24#define R_UART_BAUD_THR 0 25#define R_UART_LSR 20 26 27#define B_UART_LSR_RXRDY BIT0 28#define B_UART_LSR_TXRDY BIT5 29#define B_UART_LSR_TEMT BIT6 30 31// Print mask see DPF and D_Xxxx 32#define DPF_MASK DpfPrintMask 33 34// Select class of messages enabled for printing 35uint32_t DpfPrintMask = 36 D_ERROR | 37 D_INFO | 38 // D_REGRD | 39 // D_REGWR | 40 // D_FCALL | 41 // D_TRN | 42 0; 43 44#ifdef NDEBUG 45// Don't generate debug code 46void dpf( uint32_t mask, char_t* bla, ...) 47{ 48 return; 49} 50 51uint8_t mgetc(void) 52{ 53 return 0; 54} 55 56uint8_t mgetch(void) 57{ 58 return 0; 59} 60 61#else 62 63#ifdef SIM 64// Use Vpi console in simulation environment 65#include <vpi_user.h> 66 67void dpf( uint32_t mask, char_t* bla, ...) 68{ 69 va_list va; 70 71 if( 0 == (mask & DPF_MASK)) return; 72 73 va_start( va, bla); 74 vpi_vprintf( bla, va); 75 va_end(va); 76} 77 78#else 79 80#ifdef EMU 81// Use standard console in windows environment 82#include <stdio.h> 83#endif 84 85// Read character from serial port 86uint8_t mgetc(void) 87{ 88#ifdef EMU 89 90 // Emulation in Windows environment uses console 91 getchar(); 92 93#else 94 uint8_t c; 95 96 while ((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) == 0); 97 c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR); 98 99 return c; 100#endif 101} 102 103 104uint8_t mgetch(void) 105{ 106#ifdef EMU 107 return 0; 108#else 109 uint8_t c = 0; 110 111 if((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) != 0) 112 { 113 c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR); 114 } 115 116 return c; 117#endif 118} 119 120// Print single character 121static void printc( 122 uint8_t c) 123{ 124#ifdef EMU 125 126 // Emulation in Windows environment uses console output 127 putchar(c); 128 129#else 130 131 // 132 // Use MMIO access to serial port on PCI 133 // while( 0 == (0x20 & inp(0x3f8 + 5))); 134 // outp(0x3f8 + 0, c); 135 // 136 while (0 137 == (B_UART_LSR_TEMT & *((volatile uint8_t*) (UartMmioBase + R_UART_LSR)))) 138 ; 139 *((volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR)) = c; 140#endif 141} 142 143// Print 0 terminated string on serial console 144static void printstr( 145 char_t *str) 146{ 147 while (*str) 148 { 149 printc(*str++); 150 } 151} 152// Print 64bit number as hex string on serial console 153// the width parameters allows skipping leading zeros 154static void printhexx( 155 uint64_t val, 156 uint32_t width) 157{ 158 uint32_t i; 159 uint8_t c; 160 uint8_t empty = 1; 161 162 // 64bit number has 16 characters in hex representation 163 for (i = 16; i > 0; i--) 164 { 165 c = *(((uint8_t *)&val) + ((i - 1) >> 1)); 166 if (((i - 1) & 1) != 0) 167 c = c >> 4; 168 c = c & 0x0F; 169 170 if (c > 9) 171 c += 'A' - 10; 172 else 173 c += '0'; 174 175 if (c != '0') 176 { 177 // end of leading zeros 178 empty = 0; 179 } 180 181 // don't print leading zero 182 if (!empty || i <= width) 183 { 184 printc(c); 185 } 186 } 187} 188// Print 32bit number as hex string on serial console 189// the width parameters allows skipping leading zeros 190static void printhex( 191 uint32_t val, 192 uint32_t width) 193{ 194 uint32_t i; 195 uint8_t c; 196 uint8_t empty = 1; 197 198 // 32bit number has 8 characters in hex representation 199 for (i = 8; i > 0; i--) 200 { 201 c = (uint8_t) ((val >> 28) & 0x0F); 202 if (c > 9) 203 c += 'A' - 10; 204 else 205 c += '0'; 206 207 val = val << 4; 208 209 if (c != '0') 210 { 211 // end of leading zeros 212 empty = 0; 213 } 214 215 // don't print leading zero 216 if (!empty || i <= width) 217 { 218 printc(c); 219 } 220 } 221} 222// Print 32bit number as decimal string on serial console 223// the width parameters allows skipping leading zeros 224static void printdec( 225 uint32_t val, 226 uint32_t width) 227{ 228 uint32_t i; 229 uint8_t c = 0; 230 uint8_t empty = 1; 231 232 // Ten digits is enough for 32bit number in decimal 233 uint8_t buf[10]; 234 235 for (i = 0; i < sizeof(buf); i++) 236 { 237 c = (uint8_t) (val % 10); 238 buf[i] = c + '0'; 239 val = val / 10; 240 } 241 242 while (i > 0) 243 { 244 c = buf[--i]; 245 246 if (c != '0') 247 { 248 // end of leading zeros 249 empty = 0; 250 } 251 252 // don't print leading zero 253 if (!empty || i < width) 254 { 255 printc(c); 256 } 257 } 258} 259 260// Consume numeric substring leading the given string 261// Return pointer to the first non-numeric character 262// Buffer reference by width is updated with number 263// converted from the numeric substring. 264static char_t *getwidth( 265 char_t *bla, 266 uint32_t *width) 267{ 268 uint32_t val = 0; 269 270 while (*bla >= '0' && *bla <= '9') 271 { 272 val = val * 10 + *bla - '0'; 273 bla += 1; 274 } 275 276 if (val > 0) 277 { 278 *width = val; 279 } 280 return bla; 281} 282 283// Consume print format designator from the head of given string 284// Return pointer to first character after format designator 285// input fmt 286// ----- --- 287// s -> s 288// d -> d 289// X -> X 290// llX -> L 291static char_t *getformat( 292 char_t *bla, 293 uint8_t *fmt) 294{ 295 if (bla[0] == 's') 296 { 297 bla += 1; 298 *fmt = 's'; 299 } 300 else if (bla[0] == 'd') 301 { 302 bla += 1; 303 *fmt = 'd'; 304 } 305 else if (bla[0] == 'X' || bla[0] == 'x') 306 { 307 bla += 1; 308 *fmt = 'X'; 309 } 310 else if (bla[0] == 'l' && bla[1] == 'l' && bla[2] == 'X') 311 { 312 bla += 3; 313 *fmt = 'L'; 314 } 315 316 return bla; 317} 318 319// Simplified implementation of standard printf function 320// The output is directed to serial console. Only selected 321// class of messages is printed (mask has to match DpfPrintMask) 322// Supported print formats: %[n]s,%[n]d,%[n]X,,%[n]llX 323// The width is ignored for %s format. 324void dpf( 325 uint32_t mask, 326 char_t* bla, 327 ...) 328{ 329 uint32_t* arg = (uint32_t*) (&bla + 1); 330 331 // Check UART MMIO base configured 332 if (0 == UartMmioBase) 333 return; 334 335 // Check event not masked 336 if (0 == (mask & DPF_MASK)) 337 return; 338 339 for (;;) 340 { 341 uint8_t x = *bla++; 342 if (x == 0) 343 break; 344 345 if (x == '\n') 346 { 347 printc('\r'); 348 printc('\n'); 349 } 350 else if (x == '%') 351 { 352 uint8_t fmt = 0; 353 uint32_t width = 1; 354 355 bla = getwidth(bla, &width); 356 bla = getformat(bla, &fmt); 357 358 // Print value 359 if (fmt == 'd') 360 { 361 printdec(*arg, width); 362 arg += 1; 363 } 364 else if (fmt == 'X') 365 { 366 printhex(*arg, width); 367 arg += 1; 368 } 369 else if (fmt == 'L') 370 { 371 printhexx(*(uint64_t*) arg, width); 372 arg += 2; 373 } 374 else if (fmt == 's') 375 { 376 printstr(*(char**) arg); 377 arg += 1; 378 } 379 } 380 else 381 { 382 printc(x); 383 } 384 } 385} 386 387#endif //SIM 388#endif //NDEBUG 389