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
dpf(uint32_t mask,char_t * bla,...)46 void dpf( uint32_t mask, char_t* bla, ...)
47 {
48 return;
49 }
50
mgetc(void)51 uint8_t mgetc(void)
52 {
53 return 0;
54 }
55
mgetch(void)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
dpf(uint32_t mask,char_t * bla,...)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
mgetc(void)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
mgetch(void)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
printc(uint8_t c)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
printstr(char_t * str)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
printhexx(uint64_t val,uint32_t width)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
printhex(uint32_t val,uint32_t width)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
printdec(uint32_t val,uint32_t width)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.
getwidth(char_t * bla,uint32_t * width)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
getformat(char_t * bla,uint8_t * fmt)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.
dpf(uint32_t mask,char_t * bla,...)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