1 /** @file 2 Serial conole output and string formating. 3 4 Copyright (c) 2013-2015 Intel Corporation. 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT 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. 21 uint32_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 35 uint32_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 46 void dpf( uint32_t mask, char_t* bla, ...) 47 { 48 return; 49 } 50 51 uint8_t mgetc(void) 52 { 53 return 0; 54 } 55 56 uint8_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 67 void 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 86 uint8_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 104 uint8_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 121 static 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 144 static 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 154 static 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 190 static 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 224 static 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. 264 static 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 291 static 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. 324 void 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