您的位置:首页 > 其它

龙芯软件开发(14)--串口输出

2006-12-31 14:52 351 查看
串口输出东西太重要了,因此,再来仔细地看看串口调用的其它函数,这样做到一目了然,没有别的疑问在里面,就可以做到庖丁解牛游刃有余。像下面的函数:
PRINTSTR(" CONFIG=")
上面这句,就是输出一串字符到串里显示出来。其实它是一个宏定义,那么它是怎么样实现输出字符串到串口上的呢?立即去找到它的宏定义,然后把它展开,最后看看它是怎么样的。宏定义如下:
[align=left]#define PRINTSTR(x) /[/align]
.rdata;98: .asciz x; .text; la a0, 98b; bal stringserial; nop

把它写得好看一些,如下:
.rdata
98: .asciz x
.text
la a0,98b
bal stringserial
nop
第一、二行是定义一串字符串保存的空间,放在只读数据段里。第三行是定义代码段开始,然后就是通过la指令获取98标号处的字符串首地址。最后跳到子函数stringserial里运行输出字符串。一定要在跳转的指令后面加入一条空指令,否则其它指令就会被执行。

现在又去查看stringserial的代码,它如下:

[align=left]LEAF(stringserial)[/align]
[align=left] move a2, ra[/align]
[align=left] addu a1, a0, s0[/align]
[align=left] lbu a0, 0(a1)[/align]
[align=left]1:[/align]
[align=left] beqz a0, 2f[/align]
[align=left] nop[/align]
[align=left] bal tgt_putchar[/align]
[align=left] addiu a1, 1[/align]
[align=left] b 1b[/align]
[align=left] lbu a0, 0(a1)[/align]
[align=left] [/align]
[align=left]2:[/align]
[align=left] j a2[/align]
[align=left] nop[/align]
END(stringserial)

上面代码,先把返回地址ra保存到a2,然后计算字符串的地址,接着通过lbu获取第一个字符,在beqz里判断是否到了字符串结束,如果没有结束就继续调用显示字符函数显示。使用addiu指令来移动字符串地址指针。
在b 1b后面还有一行lbu a0,0(a1)。由于龙芯是流水线的CPU,当跳转发生时,已经把后面那一条指令解释执行完成了,所以a0里总是保存最新的字符。

还用到一个子函数hexserial以16进制的方式输出寄存器的值,它的代码如下:
[align=left]LEAF(hexserial)[/align]
[align=left] move a2, ra[/align]
[align=left] move a1, a0[/align]
[align=left] li a3, 7[/align]
[align=left]1:[/align]
[align=left] rol a0, a1, 4[/align]
[align=left] move a1, a0[/align]
[align=left] and a0, 0xf[/align]
[align=left] la v0, hexchar[/align]
[align=left] addu v0, s0[/align]
[align=left] addu v0, a0[/align]
[align=left] bal tgt_putchar[/align]
[align=left] lbu a0, 0(v0)[/align]
[align=left] [/align]
[align=left] bnez a3, 1b[/align]
[align=left] addu a3, -1[/align]
[align=left] [/align]
[align=left] j a2[/align]
[align=left] nop[/align]
END(hexserial)

在函数的开始处,先保存返回地址,保存显示的寄存器值,然后把32位的值分成8个字符显示,li a3,7就是做8次的计数。
bnez a3,1b
addu a3,-1
同时也是利用跳转同时改变a3的值。
要显示16进制的值,是使用查表法实现的。hexchar是表格的首地址。

下面再看怎么样实现显示一个字符的代码:
[align=left]LEAF(tgt_putchar)[/align]
[align=left]# la v0, COM1_BASE_ADDR[/align]
[align=left] la v0, COM3_BASE_ADDR[/align]
[align=left]1:[/align]
[align=left] lbu v1, NSREG(NS16550_LSR)(v0)[/align]
[align=left] and v1, LSR_TXRDY[/align]
[align=left] beqz v1, 1b[/align]
[align=left] nop[/align]
[align=left] [/align]
[align=left] sb a0, NSREG(NS16550_DATA)(v0)[/align]
[align=left] [/align]
[align=left] move v1, v0[/align]
[align=left] la v0, COM3_BASE_ADDR[/align]
[align=left] bne v0, v1, 1b[/align]
[align=left] nop[/align]
[align=left] [/align]
[align=left] j ra[/align]
[align=left] nop [/align]
END(tgt_putchar)

上面的代码是从串口3显示字符出来。先要判断串口是否可以发送数据,如果不能发送,就循环查询,直到可以发送为止。

到这里已经把串口看完了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: