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

串口输出东西太重要了,因此,再来仔细地看看串口调用的其它函数,这样做到一目了然,没有别的疑问在里面,就可以做到庖丁解牛游刃有余。像下面的函数:
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显示字符出来。先要判断串口是否可以发送数据,如果不能发送,就循环查询,直到可以发送为止。
 
到这里已经把串口看完了。
 

转载于:https://www.cnblogs.com/ajuanabc/archive/2006/12/31/2464400.html

你可能感兴趣的:(龙芯软件开发(14)--串口输出)