From d3991147c77c86ff58defbfb4cae54533f8a995c Mon Sep 17 00:00:00 2001 From: FyloZ Date: Sun, 22 Feb 2026 22:50:35 -0500 Subject: [PATCH] Additional printf formats --- src/kernel/kernel.c | 2 +- src/kernel/riscv64/qemu/uart.c | 82 ++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 25c75cd..430651c 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -7,7 +7,7 @@ void kmain(void) { uart_init(); - print("Hello world, %s!\n", ARCH); + print("Hello world, %x!\n", 0xff); power_off(); } diff --git a/src/kernel/riscv64/qemu/uart.c b/src/kernel/riscv64/qemu/uart.c index 3056318..a1ebc46 100644 --- a/src/kernel/riscv64/qemu/uart.c +++ b/src/kernel/riscv64/qemu/uart.c @@ -1,6 +1,8 @@ #include #include "../../uart.h" +#include + // QEMU emulates the NS16550A UART // The UART is memory mapped at 0x1000000 #define UART_ADDR 0x10000000 @@ -36,9 +38,16 @@ void uart_puts(const char *line) { uart_putchar('\n'); } +#define DIGIT_TO_STR(digit) ('0' + (digit)) +#define DIGIT_TO_HEX(digit) ('0' + (digit) + ((digit < 10 ? 0 : 'a' - '0' - 10))) + // Basic implementation of printf supporting the following formats: // - c: Character // - s: String of characters +// - d, i: Signed integer +// - u: Unsigned integer +// - x: Unsigned hexadecimal +// - p: Pointer address // - %: Literal '%' void uart_vprintf(const char *restrict format, va_list args) { while (*format) { @@ -57,6 +66,79 @@ void uart_vprintf(const char *restrict format, va_list args) { case 's': // String uart_print(va_arg(args, char*)); break; + case 'd': + case 'i': { + // TODO: This implementation breaks when the number starts with '0'. Check when debugging is possible? + int num = va_arg(args, int); + if (num == INT_MIN) { + uart_print("-2147483648"); + break; + } + + if (num < 0) { + uart_putchar('-'); + num = -num; + } + + const char lsh = DIGIT_TO_STR(num % 10); + num /= 10; + + // Convert the number into a buffer of characters + // The buffer will be reversed (the last digit will be first) + char buf[9]; // There can't be more than 10 digits in an integer, -1 because of lsh + char *buf_ptr = buf; + while (num > 0) { + *buf_ptr++ = DIGIT_TO_STR(num % 10); + num /= 10; + } + + // Print the characters in correct order + while (buf_ptr != buf) { + uart_putchar(*--buf_ptr); + } + + uart_putchar(lsh); + } + break; + case 'u': { + // Similar as the signed variant, without support for negatives + unsigned int num = va_arg(args, unsigned int); + const char lsh = DIGIT_TO_STR(num % 10); + num /= 10; + + char buf[9]; + char *buf_ptr = buf; + while (num > 0) { + *buf_ptr++ = DIGIT_TO_STR(num % 10); + num /= 10; + } + + while (buf_ptr != buf) { + uart_putchar(*--buf_ptr); + } + uart_putchar(lsh); + } + break; + case 'p': + uart_print("0x"); + case 'x': { + unsigned int num = va_arg(args, unsigned int); + const char lsh = DIGIT_TO_HEX(num % 16); + num /= 16; + + char buf[7]; + char *buf_ptr = buf; + while (num > 0) { + *buf_ptr++ = DIGIT_TO_HEX(num % 16); + num /= 16; + } + + while (buf_ptr != buf) { + uart_putchar(*--buf_ptr); + } + uart_putchar(lsh); + } + break; case '%': // Literal '%' uart_putchar('%'); break;