RISCV基础开发(七)

gewenbin
gewenbin
gewenbin
188
文章
15
评论
2021年8月18日22:29:01 评论 835

QEMU裸机开发之格式化打印

在前面的程序中我们实现了简单的字符串输出函数,在实际使用时,我们还需要进行格式化打印,比如打印某个变量的值,按十进制或者十六进制打印等等,本章节我们在“uart.c”中实现一个简单的printf函数,用于后续程序的调试,在“uart.c”中添加的代码如下所示。

//printf functions
static char digits[] = "0123456789abcdef";

static void print_int(int xx, int base, int sign)
{
    char buf[16];
    int i;
    unsigned int x;

    if(sign && (sign = xx < 0))
        x = -xx;
    else
        x = xx;

    i = 0;
    do {
        buf[i++] = digits[x % base];
    } while((x /= base) != 0);

    if(sign)
        buf[i++] = '-';

    while(--i >= 0)
        uart_putc(buf[i]);
}

static void print_ptr(unsigned long x)
{
    int i;
    uart_putc('0');
    uart_putc('x');

    for (i = 0; i < (sizeof(unsigned long) * 2); i++, x <<= 4)
        uart_putc(digits[x >> (sizeof(unsigned long) * 8 - 4)]);
}

// Print to the console. only understands %d, %x, %p, %s.
void printf(char *fmt, ...)
{
    va_list ap;
    int i, c;
    char *s;

    if (fmt == 0)
        return;

    va_start(ap, fmt);
    for(i = 0; (c = fmt[i] & 0xff) != 0; i++) {
        if(c != '%'){
            uart_putc(c);
            continue;
        }

        c = fmt[++i] & 0xff;
        if(c == 0)
            break;

        switch(c){
        case 'd':
            print_int(va_arg(ap, int), 10, 1);
            break;

        case 'x':
            print_int(va_arg(ap, int), 16, 1);
            break;

        case 'p':
            print_ptr(va_arg(ap, unsigned long));
            break;

        case 's':
            if((s = va_arg(ap, char*)) == 0)
                s = "(null)";

            for(; *s; s++)
                uart_putc(*s);
            break;

        case '%':
            uart_putc('%');
            break;

        default:
            // Print unknown % sequence to draw attention.
            uart_putc('%');
            uart_putc(c);
            break;
        }
    }
}

这个printf实现参考xv6,功能也很简单,主要有以下几个功能:

  • %d:32位数据按十进制打印。
  • %x:32位数据按十六进制打印。
  • %p:按16进制打印指针数值。
  • %s:打印字符串。

有了这几个功能之后,基本能对付大部分的打印调试需求了,将“start.c”中的打印换成printf,如下所示。

#include "uart.h"

void start(void)
{
    printf("%s %d.\r\n", __func__, __LINE__);
}

在命令行执行“make qemu”,可以在最后看到打印的函数名以及行号信息,如下所示。

gewenbin@gewenbin-virtual-machine:~/Desktop/qemu_test/lesson2$ make qemu
riscv64-unknown-elf-gcc -Wall -Werror -O -fno-omit-frame-pointer -ggdb -mcmodel=medany -ffreestanding -fno-common -nostdlib -mno-relax -I. -fno-stack-protector -fno-pie -no-pie   -c -o start.o start.c
riscv64-unknown-elf-gcc -Wall -Werror -O -fno-omit-frame-pointer -ggdb -mcmodel=medany -ffreestanding -fno-common -nostdlib -mno-relax -I. -fno-stack-protector -fno-pie -no-pie   -c -o uart.o uart.c
riscv64-unknown-elf-ld -z max-page-size=4096 -T kernel.ld -o kernelimage entry.o start.o uart.o 
riscv64-unknown-elf-objdump -S kernelimage > kernel.asm
riscv64-unknown-elf-objdump -t kernelimage | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$/d' > kernel.sym
qemu-system-riscv64 -machine virt -bios none -kernel kernelimage -m 128M -smp 1 -nographic
start 5.

工程源码:链接:https://pan.baidu.com/s/1TnTYr7mywdKj5bxpdmWnyA,提取码:q772,见lesson2。

gewenbin
  • 本文由 发表于 2021年8月18日22:29:01
  • 转载请务必保留本文链接:http://www.databusworld.cn/10523.html
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: