Output Char to Screen
1.Introduction
与CPU相连的各种硬件,如内存条RAM,显卡,网卡等,CPU在控制它们的时候,把它们都当作内存对待。把它们总的看作一个由若干存储单元组成的逻辑存储器,这个逻辑存储器就是我们所说的内存地址空间。如8086CPU的内存地址空间的地址段分配如下:
Figure 1. 8086CPU内存地址空间分配
由上图可知,从址00000H~9FFFFH的内存单元中读取数据,实际上就是读取主随机存储器中的数据;向地址A0000H~BFFFFH的内存单元中写数据,就是向显存中写入数据,这些数据会被显示卡输出到显示器上。
2. Output Char in Debug
通过Debug程序的E命令可以修改内存中的数据。根据上述显存地址,通过Debug的E命令向显存中写入数据,看看会有什么情况发生?
Figure 2. Modify memory in Debug
由上图可知,在控制窗口的上面输出了彩色的字母。这是因为在8086CPU中,内存地址空间B8000H~BFFFFH共32KB的空间为80X25彩色字符模式的显示缓冲区。向这个地址空间写入数据,写入的内容将立即出现在显示器上。
在80X25彩色字符模式下,显示器可以显示25行,每行80个字符,每个字符可以有256种属性(背景色、前景色、闪烁、高亮等组合属性)。这样一个字符在显示缓冲区中就要占两个字节,分别存放字符的ASCII码和属性。80X25模式下,一屏内容在显示缓冲区中共占4000个字节。在一行中,一个字符占两个字节的存储空间(一个字),低位字节存储字符的ASCII码,高位字节存储字符的属性。一行共有80个字符,占160字节。
关于文字颜色的属性可以参考王爽的《汇编语言》。
Figure 3. ASCII code
如果要输出WELCOME,则可以在Debug中输入如下命令:
Figure 4. Output WELCOME
3. Output Char by ASM
如果要编写汇编程程序来输出一段字符到屏幕的话,只涉及到向B8000H内存中写入数据。怎么向指定的内存中写入数据呢?
CPU要读写一个内存单元的时候,必须先给出这个内存单元的地址,在8086CPU中,内存地址由段地址和偏移地址组成。8086CPU中有一个DS寄存器通用来存放要访问数据的段地址。但是8086CPU不支持将数据直接送入段寄存器的操作,所以mov ds,1000h这条指令是非法的。那么如何将数据送入段寄存器呢?只好用一个寄存器来进行中转,如mov ax,1000h, mov ds,ax
Debug程序和汇编译程序MASM对指令的处理还有不同。我们在Debug中写过这种指令:
mov ax,[0] 表示将ds:0处的数据送入寄存器AX中。但是在汇编程序MASM中,指令被编译器当作mov ax,0。注意上述的一些事项,就可以编写一个汇编程序,来输出WELCOME TO ASM!到屏幕了。程序代码如下所示:
codeseg segment
mov bx,0b800h
mov ds,bx
mov ds:[ 00 ],0257h
mov ds:[ 02 ],0245h
mov ds:[ 04 ],034ch
mov ds:[ 06 ],0443h
mov ds:[ 08 ],054fh
mov ds:[ 10 ],064dh
mov ds:[ 12 ],0745h
mov ds:[ 14 ],0220h
mov ds:[ 16 ],0854h
mov ds:[ 18 ],094fh
mov ds:[ 20 ],0220h
mov ds:[ 22 ],1241h
mov ds:[ 24 ],1353h
mov ds:[ 26 ],144dh
mov ds:[ 28 ],1521h
mov ax,4c00h
int 21h
codeseg ends
end
编译连接后,运行程序输出如下图所示:
Figure 5. Output Welcome to ASM!
指令mov ax,[bx]中,内存单元的偏移地址由bx给出,而段地址默认在DS寄存器中。我们可以在访问内存单元的指令中显式地给出内存单元的段地址所在的段寄存器。如mov ax,ds:[bx]。如上述的代码中用到mov ds:[00],0257h。这些出现在内存单元的指令中,用于显式地指明内存单元的段地址的ds:, cs:, ss:, es:,在汇编语言中称为段前缀。
综上所述,如果想实现下C语言中的printf()函数,要考虑的事情还是很多的。