本文将pmon中的libc移植到龙芯1c库中,用于龙芯1c的纯裸机编程。实际上标准的c库libc不应该属于龙芯1c库,狭义的“龙芯1c库”应该是像“STM32库”那样只封装了各个外设的功能,这里说的“龙芯1c库”我认为应该是“广义的”,泛指裸机编程需要的各种常用功能的集合。先不咬文嚼字了,暂且这样理解吧。
除了libc外,标准数学库libm的移植也是类似的。
龙芯1c库的git地址是https://gitee.com/caogos/OpenLoongsonLib1c
为什么需要移植libc?因为需要用到libc中的一些函数啊。比如printf,strcpy,strcat,strstr等等。
Libc中包括两类函数:字符串处理相关的函数(比如strcpy, strcat, strstr等等)和文件相关的函数(比如fopen, fclose, fgetc, fputc, fread, fwrite, printf等等)。对于单片机的裸机编程来说,只需要字符串处理相关的函数和printf就够了,其中printf是个特例,是我们移植的唯一一个文件相关的函数。
使用printf()函数打印调试信息时非常实用、非常常见的。而printf()函数的作用就是将字符串格式化,即在字符串中携带一些变量的值,比如用printf()函数打印“当前温度值=xxx”。
Printf()在格式化字符串的时候就需要使用各种字符串处理函数。除此之外,在解析或组建一些协议时,可能也需要使用字符串相关的一些函数。
参考pmon,Pmon本身就是一个纯粹的裸机程序,里面也包含了libc、libm。先来看下pmon里面的libc目录长什么样。如下
细心的读者可能已经注意到了,libc文件夹中的文件名好像有点熟悉也,对不对?^__^,对,就是在常用的strcpy, strcat, strcmp, strlen等函数后面加了“.c”。难倒每个函数单独放一个c文件吗?经过验证,是的,同一个源文件中,要么只有一个函数,要么就是功能相似的多个函数。比如:strcpy()和strlcpy()都位于strcpy.c中。下面来看下只有一个函数的情况,比如strcat.c,如下
其它的函数也类似,好,明白了这点就好移植了。说是移植,其实就是把需要的文件拷贝过去,然后编译,根据错误提示逐个解决即可。大致思路就这样。
Printf()是文件相关的函数,功能是把信息打印到文件。而对于裸机编程来说没有文件系统那一套,所以需要对printf稍微修改一下。下面把修改前和修改后的printf源码贴出来
Pmon中的printf()源码(修改前),
#include
#include
/** printf(fmt,va_alist) -- print formatted output to stdout */
extern unsigned int output_mode;
int
printf (const char *fmt, ...)
{
int len;
va_list ap;
#ifdef FAST_STARTUP
if (output_mode == 0)
return 0;
#endif
va_start(ap, fmt);
len = vfprintf (stdout, fmt, ap);
va_end(ap);
return (len);
}
(修改后的)龙芯1c库中的printf源码
#include
#include
#include "../lib/ls1c_uart.h"
#define PRINTF_BUF_SIZE (512)
int printf (const char *fmt, ...)
{
int len;
va_list ap;
char buf[PRINTF_BUF_SIZE];
va_start(ap, fmt);
// 格式化字符串
len = vsprintf (buf, fmt, ap);
// 调用龙芯1c库中的串口函数打印字符串
uart_debug_print(buf);
va_end(ap);
return (len);
}
函数vsprintf()就是将传递给printf()的入参按照指定的格式,将其转换为一个字符串并放入buf中,函数uart_debug_print()就只需要一个字符一个字符慢慢发送即可。
函数uart_debug_print()源码如下
/*
* 在调试串口打印字符串
* @str 待打印的字符串
*/
void uart_debug_print(const char *str)
{
uart_print(debug_uart_info.UARTx, str);
return ;
}
函数uart_print()的源码为
/*
* 打印一个字符串到指定串口
* @uartx 串口号
* @str 待打印的字符串
*/
void uart_print(ls1c_uart_t uartx, const char *str)
{
while ('\0' != *str) // 判断是否为字符串结束符
{
uart_putc(uartx, *str); // 发送一个字符
str++;
}
return ;
}
函数uart_putc()就是操作cpu的寄存器发送一个字符。
/*
* 发送一个字节
* @uartx 串口号
* @ch 待发送的字符串
*/
void uart_putc(ls1c_uart_t uartx, unsigned char ch)
{
void *uart_base = uart_get_base(uartx);
// 等待
while (FALSE == uart_is_transmit_empty(uartx))
;
// 发送
reg_write_8(ch, uart_base + LS1C_UART_DAT_OFFSET);
return ;
}
前面分析了函数printf()的流程,对于打印字符串和整数来说,有了libc中的字符串处理函数就足够了。但是要打印浮点数,首先需要支持浮点运算(不论是软浮点,还是硬浮点都可以),其次是需要几个libm中的函数。博文【龙芯1c库】移植硬浮点FPU讲了如何使能龙芯1c的FPU,这里重点讨论一下printf()是如何打印浮点数的,需要使用到那些libm函数。
函数printf()中调用函数vsprintf()将浮点数转换为字符串并打印出来,下面来看下是如何转换的,函数vsprintf()中打印浮点相关的代码如下
#ifdef FLOATINGPT
else if (strchr ("eEfgG", *s)) {
dbl = va_arg(ap, double);
dtoa (d, dbl, *s, width, trunc);
trunc = 0;
}
#endif
从代码可知,首先定义宏FLOATINGPT,否则这段代码将不会被编译,即printf() 将不支持打印浮点数。宏FLOATINGPT定义如下
// printf支持打印浮点,如果不需要打印浮点,则注释掉该宏
#define FLOATINGPT
假设定义了宏FLOATINGPT,那么代码中每次调用printf()函数时,都会执行这段代码。这段代码的含义是,调用函数strchr()判断是否有“eEfgG”中的至少其中一个字符,如果有,则说明需要打印浮点数。即printf()的参数中有%e、%E、%f、%g或者%G。
然后就是调用dtoa()将浮点数转换为字符串,其中dtoa()中会调用一些libm中的函数,具体就自己查看源码吧。我已经把相关函数从pmon的libm中移植到龙芯1c库中了,直接使用printf()即可。这里主要是想提一下,宏FLOATINGPT控制printf()是否支持打印浮点。
Pmon中是把libc中的源文件编译为静态库libc.a,然后再与其它源文件一起编译链接的。考虑到目前龙芯1c库中的源文件个数并不多,暂时没有先把libc编译为libc.a,而是和其它源文件一样,直接把c文件编译为.o,然后直接连接。
但这里还是顺便把pmon中生成libc.a的过程提一下。
首先还是需要把c文件编译为.o文件,然后再用ar和ranlib生成libc.a。pmon中libc的完整的Makefile如下
LIB=c
NOPIC=
MACHINE= ${XMACHINE}
MACHINE_ARCH= ${XMACHINE_ARCH}
CURDIR=$(shell pwd)
M= ${CURDIR}/arch/${MACHINE_ARCH}
CPPFLAGS= -I$M ${CLIBCPPFLAGS} -U_KERNEL
VPATH+= ${M} ${CLIBDIR}
include ${M}/Makefile.inc
# Files to clean up
CLEANFILES+= ${OBJDIR}/lib${LIB}.a
include ${PMONDIR}/tools/scripts/pmon.lib.gmk
${OBJDIR}/lib${LIB}.a: ${OBJS}
@echo building standard ${LIB} library
@rm -f $@
@${AR} cq $@ ${OBJS}
${RANLIB} $@
注意,@表示在make时不输出make的信息(类似Windows下的echo off)。所以想要把完整的编译过程打印出来,需要把命令前面的@去掉。完整的编译过程如下
building standard c library
mipsel-linux-ar cq /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/libc.a /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/abs.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/argvize.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/atob.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/atof.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/atoi.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/atol.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/bzero.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/bcmp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/calloc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/cc2str.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/close.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/ctype_.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/dbl2asci.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/errno.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/ethers.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/exit.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fclose.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/feof.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fflush.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/ffs.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fls.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fgetc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fgets.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fileno.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fprintf.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fputs.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fread.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fseek.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fwrite.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getchar.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/gethostnamadr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getopt.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getprotoname.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/gets.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getservbyname.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getservent.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getword.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/index.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/inet_addr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/lseek.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/malloc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/memchr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/memset.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/misc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/modf.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/open.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/pmalloc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/printf.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/putc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/putchar.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/puts.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/qsort.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/queue.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/rand.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/read.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/realloc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/recv.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/res_comp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/res_init.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/res_mkquery.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/res_query.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/res_send.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/rindex.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/sbrk.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/scanf.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/send.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/signal.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/sigsetops.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/sizemem.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/sprintf.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/stdio.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/str2cc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/str_fmt.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strbalp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strbequ.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strcasecmp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strcat.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strccat.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strchr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strcmp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strcpy.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strcspn.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strdchr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strempty.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strichr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/striequ.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/stristr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strlen.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strmerge.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strncat.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strnchr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strncmp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strncpy.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strnwrd.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strpat.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strpbrk.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strposn.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strrchr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strrpset.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strrrot.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strrset.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strset.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strsort.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strspn.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strstr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strtok.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strtoupp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/terms.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/time.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tolower_.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/toupper_.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/ungetc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/vfprintf.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/vsprintf.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/write.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getbaud.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcdrain.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcflow.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcflush.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcgetattr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcgetpgrp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcsendbreak.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcsetattr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcsetpgrp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/cfgetispeed.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/cfgetospeed.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/cfmakeraw.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/cfsetispeed.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/cfsetospeed.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/cfsetspeed.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/ulmin.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/lmin.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/ioctl.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/filefs.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/parseurl.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/crc32.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/poweroff.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/reboot.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/video_set_lut.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/longjmp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/ovbcopy.o
mipsel-linux-ranlib /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/libc.a
虽然libc的各个函数可能都单独在一个源文件中,但是他们都按照惯例分门别类位于几个常见的头文件,比如stdio.h stdlib.h string.h……。常常把这几个头文件单独放一个文件夹,然后把该文件夹的路径添加到Makefile中的变量VPATH中,如下
VPATH += include
这样就可以在其它源文件中使用了。用法不变,如下
#include
#include
……
感谢阅读!