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