/* * BSD-3-Clause License * * Copyright (c) 2016, Matt Redfearn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #define PRINT_BUF_LEN 64 typedef __builtin_va_list va_list; #define va_start(v,l) __builtin_va_start(v,l) #define va_end(v) __builtin_va_end(v) #define va_arg(v,l) __builtin_va_arg(v,l) #define va_copy(d,s) __builtin_va_copy(d,s) static void simple_outputchar(char **str, char c) { if (str) { **str = c; ++(*str); } else { uart_send(c); } } enum flags { PAD_ZERO = 1, PAD_RIGHT = 2 }; static int prints(char **out, const char *string, int width, int flags) { int pc = 0, padchar = ' '; if (width > 0) { int len = 0; const char *ptr; for (ptr = string; *ptr; ++ptr) ++len; if (len >= width) width = 0; else width -= len; if (flags & PAD_ZERO) padchar = '0'; } if (!(flags & PAD_RIGHT)) { for (; width > 0; --width) { simple_outputchar(out, padchar); ++pc; } } for (; *string; ++string) { simple_outputchar(out, *string); ++pc; } for (; width > 0; --width) { simple_outputchar(out, padchar); ++pc; } return pc; } // this function print number `i` in the base of `base` (base > 1) // `sign` is the flag of print signed number or unsigned number // `width` and `flags` mean the length of printed number at least `width`, // if the length of number is less than `width`, choose PAD_ZERO or PAD_RIGHT // `letbase` means uppercase('A') or lowercase('a') when using hex // you may need to call `prints` // you do not need to print prefix like "0x", "0"... // Remember the most significant digit is printed first. static int printk_write_num(char **out, long long i, int base, int sign, int width, int flags, int letbase) { char print_buf[PRINT_BUF_LEN]; char *s; int t, neg = 0, pc = 0; unsigned long long u = i; if (i == 0) { print_buf[0] = '0'; print_buf[1] = '\0'; return prints(out, print_buf, width, flags); } if (sign && base == 10 && i < 0) { neg = 1; u = -i; } // TODO: fill your code here // store the digitals in the buffer `print_buf`: // 1. the last postion of this buffer must be '\0' // 2. the format is only decided by `base` and `letbase` here int len = 0; s = print_buf + 1; while (u > 0) { t = u % base; u /= base; if (t <= 9) s[len++] = t + '0'; else s[len++] = t - 10 + (letbase ? 'a': 'A'); } s[len] = '\0'; // swap print_buf char ch; for (int i = 0; i < len / 2; i++) { ch = s[i]; s[i] = s[len - 1 - i]; s[len - 1 - i] = ch; } if (neg) { if (width && (flags & PAD_ZERO)) { simple_outputchar(out, '-'); ++pc; --width; } else { *--s = '-'; } } return pc + prints(out, s, width, flags); } static int simple_vsprintf(char **out, const char *format, va_list ap) { int width, flags; int pc = 0; char scr[2]; union { char c; char *s; int i; unsigned int u; long li; unsigned long lu; long long lli; unsigned long long llu; short hi; unsigned short hu; signed char hhi; unsigned char hhu; void *p; } u; for (; *format != 0; ++format) { if (*format == '%') { ++format; width = flags = 0; if (*format == '\0') break; if (*format == '%') goto out; if (*format == '-') { ++format; flags = PAD_RIGHT; } while (*format == '0') { ++format; flags |= PAD_ZERO; } if (*format == '*') { width = va_arg(ap, int); format++; } else { for (; *format >= '0' && *format <= '9'; ++format) { width *= 10; width += *format - '0'; } } switch (*format) { case ('d'): u.i = va_arg(ap, int); pc += printk_write_num(out, u.i, 10, 1, width, flags, 'a'); break; case ('u'): u.u = va_arg(ap, unsigned int); pc += printk_write_num(out, u.u, 10, 0, width, flags, 'a'); break; case ('o'): u.u = va_arg(ap, unsigned int); pc += printk_write_num(out, u.u, 8, 0, width, flags, 'a'); break; case ('b'): u.u = va_arg(ap, unsigned int); pc += printk_write_num(out, u.u, 2, 0, width, flags, 'a'); break; case ('x'): u.u = va_arg(ap, unsigned int); pc += printk_write_num(out, u.u, 16, 0, width, flags, 'a'); break; case ('X'): u.u = va_arg(ap, unsigned int); pc += printk_write_num(out, u.u, 16, 0, width, flags, 'A'); break; case ('p'): u.lu = va_arg(ap, unsigned long); pc += printk_write_num(out, u.lu, 16, 0, width, flags, 'a'); break; case ('c'): u.c = va_arg(ap, int); scr[0] = u.c; scr[1] = '\0'; pc += prints(out, scr, width, flags); break; case ('s'): u.s = va_arg(ap, char *); pc += prints(out, u.s ? u.s : "(null)", width, flags); break; case ('l'): ++format; switch (*format) { case ('d'): u.li = va_arg(ap, long); pc += printk_write_num(out, u.li, 10, 1, width, flags, 'a'); break; case ('u'): u.lu = va_arg(ap, unsigned long); pc += printk_write_num(out, u.lu, 10, 0, width, flags, 'a'); break; case ('o'): u.lu = va_arg(ap, unsigned long); pc += printk_write_num(out, u.lu, 8, 0, width, flags, 'a'); break; case ('x'): u.lu = va_arg(ap, unsigned long); pc += printk_write_num(out, u.lu, 16, 0, width, flags, 'a'); break; case ('X'): u.lu = va_arg(ap, unsigned long); pc += printk_write_num(out, u.lu, 16, 0, width, flags, 'A'); break; case ('l'): ++format; switch (*format) { case ('d'): u.lli = va_arg(ap, long long); pc += printk_write_num(out, u.lli, 10, 1, width, flags, 'a'); break; case ('u'): u.llu = va_arg(ap, unsigned long long); pc += printk_write_num(out, u.llu, 10, 0, width, flags, 'a'); break; case ('o'): u.llu = va_arg(ap, unsigned long long); pc += printk_write_num(out, u.llu, 8, 0, width, flags, 'a'); break; case ('x'): u.llu = va_arg(ap, unsigned long long); pc += printk_write_num(out, u.llu, 16, 0, width, flags, 'a'); break; case ('X'): u.llu = va_arg(ap, unsigned long long); pc += printk_write_num(out, u.llu, 16, 0, width, flags, 'A'); break; default: break; } break; default: break; } break; case ('h'): ++format; switch (*format) { case ('d'): u.hi = va_arg(ap, int); pc += printk_write_num(out, u.hi, 10, 1, width, flags, 'a'); break; case ('u'): u.hu = va_arg(ap, unsigned int); pc += printk_write_num(out, u.lli, 10, 0, width, flags, 'a'); break; case ('o'): u.hu = va_arg(ap, unsigned int); pc += printk_write_num(out, u.lli, 8, 0, width, flags, 'a'); break; case ('x'): u.hu = va_arg(ap, unsigned int); pc += printk_write_num(out, u.lli, 16, 0, width, flags, 'a'); break; case ('X'): u.hu = va_arg(ap, unsigned int); pc += printk_write_num(out, u.lli, 16, 0, width, flags, 'A'); break; case ('h'): ++format; switch (*format) { case ('d'): u.hhi = va_arg(ap, int); pc += printk_write_num(out, u.hhi, 10, 1, width, flags, 'a'); break; case ('u'): u.hhu = va_arg(ap, unsigned int); pc += printk_write_num(out, u.lli, 10, 0, width, flags, 'a'); break; case ('o'): u.hhu = va_arg(ap, unsigned int); pc += printk_write_num(out, u.lli, 8, 0, width, flags, 'a'); break; case ('x'): u.hhu = va_arg(ap, unsigned int); pc += printk_write_num(out, u.lli, 16, 0, width, flags, 'a'); break; case ('X'): u.hhu = va_arg(ap, unsigned int); pc += printk_write_num(out, u.lli, 16, 0, width, flags, 'A'); break; default: break; } break; default: break; } break; default: break; } } else { out: simple_outputchar(out, *format); ++pc; } } if (out) **out = '\0'; return pc; } void printk(const char *fmt, ...) { va_list va; va_start(va, fmt); simple_vsprintf(NULL, fmt, va); va_end(va); } void break_point() { printk("[ChCore] Lab stalling ... \n"); }