龙芯软件开发(14)--串口输出
2006-12-31 14:52
302 查看
串口输出东西太重要了,因此,再来仔细地看看串口调用的其它函数,这样做到一目了然,没有别的疑问在里面,就可以做到庖丁解牛游刃有余。像下面的函数:
PRINTSTR(" CONFIG=")
上面这句,就是输出一串字符到串里显示出来。其实它是一个宏定义,那么它是怎么样实现输出字符串到串口上的呢?立即去找到它的宏定义,然后把它展开,最后看看它是怎么样的。宏定义如下:
#define PRINTSTR(x) /
.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的代码,它如下:
LEAF(stringserial)
move a2, ra
addu a1, a0, s0
lbu a0, 0(a1)
1:
beqz a0, 2f
nop
bal tgt_putchar
addiu a1, 1
b 1b
lbu a0, 0(a1)
2:
j a2
nop
END(stringserial)
上面代码,先把返回地址ra保存到a2,然后计算字符串的地址,接着通过lbu获取第一个字符,在beqz里判断是否到了字符串结束,如果没有结束就继续调用显示字符函数显示。使用addiu指令来移动字符串地址指针。
在b 1b后面还有一行lbu a0,0(a1)。由于龙芯是流水线的CPU,当跳转发生时,已经把后面那一条指令解释执行完成了,所以a0里总是保存最新的字符。
还用到一个子函数hexserial以16进制的方式输出寄存器的值,它的代码如下:
LEAF(hexserial)
move a2, ra
move a1, a0
li a3, 7
1:
rol a0, a1, 4
move a1, a0
and a0, 0xf
la v0, hexchar
addu v0, s0
addu v0, a0
bal tgt_putchar
lbu a0, 0(v0)
bnez a3, 1b
addu a3, -1
j a2
nop
END(hexserial)
在函数的开始处,先保存返回地址,保存显示的寄存器值,然后把32位的值分成8个字符显示,li a3,7就是做8次的计数。
bnez a3,1b
addu a3,-1
同时也是利用跳转同时改变a3的值。
要显示16进制的值,是使用查表法实现的。hexchar是表格的首地址。
下面再看怎么样实现显示一个字符的代码:
LEAF(tgt_putchar)
# la v0, COM1_BASE_ADDR
la v0, COM3_BASE_ADDR
1:
lbu v1, NSREG(NS16550_LSR)(v0)
and v1, LSR_TXRDY
beqz v1, 1b
nop
sb a0, NSREG(NS16550_DATA)(v0)
move v1, v0
la v0, COM3_BASE_ADDR
bne v0, v1, 1b
nop
j ra
nop
END(tgt_putchar)
上面的代码是从串口3显示字符出来。先要判断串口是否可以发送数据,如果不能发送,就循环查询,直到可以发送为止。
到这里已经把串口看完了。
PRINTSTR(" CONFIG=")
上面这句,就是输出一串字符到串里显示出来。其实它是一个宏定义,那么它是怎么样实现输出字符串到串口上的呢?立即去找到它的宏定义,然后把它展开,最后看看它是怎么样的。宏定义如下:
#define PRINTSTR(x) /
.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的代码,它如下:
LEAF(stringserial)
move a2, ra
addu a1, a0, s0
lbu a0, 0(a1)
1:
beqz a0, 2f
nop
bal tgt_putchar
addiu a1, 1
b 1b
lbu a0, 0(a1)
2:
j a2
nop
END(stringserial)
上面代码,先把返回地址ra保存到a2,然后计算字符串的地址,接着通过lbu获取第一个字符,在beqz里判断是否到了字符串结束,如果没有结束就继续调用显示字符函数显示。使用addiu指令来移动字符串地址指针。
在b 1b后面还有一行lbu a0,0(a1)。由于龙芯是流水线的CPU,当跳转发生时,已经把后面那一条指令解释执行完成了,所以a0里总是保存最新的字符。
还用到一个子函数hexserial以16进制的方式输出寄存器的值,它的代码如下:
LEAF(hexserial)
move a2, ra
move a1, a0
li a3, 7
1:
rol a0, a1, 4
move a1, a0
and a0, 0xf
la v0, hexchar
addu v0, s0
addu v0, a0
bal tgt_putchar
lbu a0, 0(v0)
bnez a3, 1b
addu a3, -1
j a2
nop
END(hexserial)
在函数的开始处,先保存返回地址,保存显示的寄存器值,然后把32位的值分成8个字符显示,li a3,7就是做8次的计数。
bnez a3,1b
addu a3,-1
同时也是利用跳转同时改变a3的值。
要显示16进制的值,是使用查表法实现的。hexchar是表格的首地址。
下面再看怎么样实现显示一个字符的代码:
LEAF(tgt_putchar)
# la v0, COM1_BASE_ADDR
la v0, COM3_BASE_ADDR
1:
lbu v1, NSREG(NS16550_LSR)(v0)
and v1, LSR_TXRDY
beqz v1, 1b
nop
sb a0, NSREG(NS16550_DATA)(v0)
move v1, v0
la v0, COM3_BASE_ADDR
bne v0, v1, 1b
nop
j ra
nop
END(tgt_putchar)
上面的代码是从串口3显示字符出来。先要判断串口是否可以发送数据,如果不能发送,就循环查询,直到可以发送为止。
到这里已经把串口看完了。
相关文章推荐
- 龙芯软件开发(14)--串口输出
- 龙芯软件开发(14)--串口输出
- [零基础学软件开发4]用c语言输出信息printf介绍
- 龙芯软件开发(33)-- USB协议深入分析
- 龙芯软件开发(1)--BIOS资料
- 龙芯软件开发(2)--汇编资料
- 龙芯软件开发(4)--主要芯片介绍
- 龙芯软件开发(6)--CPU龙芯2E
- 龙芯软件开发(7)--编译PMON指南
- 龙芯软件开发(13)--配置南桥进入调试新天地
- 龙芯软件开发(15)-- 搬家前的准备
- 龙芯软件开发(17)-- 初始化龙芯2E缓存
- 龙芯软件开发(19)-- C函数入口
- 龙芯软件开发(24)-- PCI设备初始化2
- Unity3d 与串口的通信程序的开发,软件硬件结合
- 【工业串口和网络软件通讯平台(SuperIO)教程】三.二次开发流程
- 龙芯软件开发(36)- USB协议深入分析 返回设备描述符
- 龙芯软件开发(38)- USB协议深入分析 设置USB地址
- 龙芯软件开发(40)- USB协议深入分析 字符串描述符
- 【工业串口和网络软件通讯平台(SuperIO)教程】六.二次开发导出数据驱动