第6章 打印函数

打印函数的原理
写操作系统必须要有打印函数,这样才方便调试。对于所有的显示适配器,文本方式下显示字符的原理都是一样的,所不同的是各种适配器的视频显示存储器(又称显存)的起始地址不同;对MDA,显存的起始地址为B000:0000,对CGA、EGA、VGA是B800:0000。每个字符的ASCII码和属性码字节存放于连续的两个字节中。在25*80的文本显示方式下,屏幕有2000个字符位置,因每个字符需要用两个字节来表示,所以显存容量需要4000B。

在显示适配器中,设置光标很重要,下面是VGA模式下设置光标的方法:
CRT控制器名称端口
索引寄存器3D4H
数据寄存器3D5H

CRT控制器中有26个寄存器,必须经索引后,才能通过 3D5端口 读写。下面是CRT控制器寄存器列表。

寄存器名称索引号写端口
( EGA/VGA/TVGA)
读端口
(EGA)
读端口
(VGA/TVGA)
地址寄存器--3D5H/3B5H 3D4H/3B5H
光标位置(高位)0EH 3D5H/3B5H3D5H/3B5H3D5H/3B5H
光标位置(低位)0FH3D5H/3B5H3D5H/3B5H3D5H/3B5H

获取光标位置的方法

outportb(0x3d4, 0x0e); //索引寄存器,选择光标位置高位寄存器

highbyte= inportb(0x3d5); //取出光标位置高位字节

outportb(0x3d4, 0x0f); //索引寄存器,选择光标位置低位寄存器

lowbyte =inportb(0x3d5); //取出光标位置低位字节

设置光标位置的方法
outportb(0x3d4, 0x0f);
outportb(0x3d5, lowbyte & 0x0ff);
outportb(0x3d4, 0x0e);
outportb(0x3d5, highbyte & 0x0ff);


打印函数的源代码

Intel处理器中IO地址和内存地址不是统一编址,有单独的IO指令。下面是IO读写命令的宏定义。

#ifndef	    _IO_H_
#define	    _IO_H_

#define	    outportb(port,value)\
__asm__ ("outb %%al,%%dx"::"a"(value),"d"(port)) 

#define	    inportb(port)({\
unsigned char _v;\
__asm__ volatile ("inb %%dx,%%al":"=a"(_v):"d"(port));\
_v;\
})


#endif
 

video.h文件的源代码

#ifndef	    _VIDEO_H_
#define	    _VIDEO_H_

//字符属性
#define	    BLACK    0x0
#define	    BLUE    0x1
#define	    GREEN    0x2
#define	    RED        0x4
#define	    WHITE    0xf
#define	    YELLOW    0xe

#define	    char_attr(backgroud,front)  (backgroud<<4|front)

void kprint(unsigned char attribute, char *string);
void printnum(unsigned char attribute, unsigned int num);
void cls();
#endif

video.c文件的源代码

#include "video.h"
#include "io.h"


unsigned char *VIDEO_MEMORY = (char *)0xb8000;

void kprint(unsigned char attribute, char *string)
{
    unsigned int curchar, vidmem_off, i;

    //得到光标位置
    outportb(0x3d4, 0x0e);         //索引寄存器,选择光标位置高位寄存器
    vidmem_off = inportb(0x3d5);    //取出光标位置高位字节
    vidmem_off <<= 8;
    outportb(0x3d4, 0x0f);        //索引寄存器,选择光标位置低位寄存器
    vidmem_off += inportb(0x3d5);    //取出光标位置低位字节
    vidmem_off <<= 1;

    while((curchar = *string++))
    {
    switch(curchar)
    {
        case '\n':
        vidmem_off = (vidmem_off/160)*160 + 160;
        break;
        
        case '\r':
        vidmem_off = (vidmem_off/160)*160;
        break;

        case '\t':
        vidmem_off += 8;
        break;

        case 8:/*Delete*/
        vidmem_off -= 2;
        VIDEO_MEMORY[vidmem_off] = 0x20;
        break;

        default:
        VIDEO_MEMORY[vidmem_off++] = curchar;
        VIDEO_MEMORY[vidmem_off++] = attribute;
        break;
    
    }

    if(vidmem_off >= 160*25)
    {
        for(i = 0; i < 160*24; i++)
        {
        VIDEO_MEMORY[i] = VIDEO_MEMORY[i+160];
        }

        for(i = 0; i < 80; i++)
        {
        VIDEO_MEMORY[(160*24)+(i*2)] = 0x20;
        VIDEO_MEMORY[(160*24)+(i*2)+1] = attribute;
            
        }
    
        vidmem_off -= 160;
    }
    }
  
    //设置光标位置  
    vidmem_off >>= 1;
    outportb(0x3d4, 0x0f);
    outportb(0x3d5, vidmem_off & 0x0ff);
    outportb(0x3d4, 0x0e);
    outportb(0x3d5, vidmem_off >> 8);
    
}



void cls(void)
{
    unsigned int i;
    for(i = 0; i < (80*25); i++)
    {
    VIDEO_MEMORY[i*2] = 0x20;
    VIDEO_MEMORY[i*2+1] = 0x07;
    }

    outportb(0x3d4, 0x0f);
    outportb(0x3d5, 0);
    outportb(0x3d4, 0x0e);
    outportb(0x3d5, 0);

}


void printnum(unsigned char attribute, unsigned int  num)
{
    unsigned char backstr[11], i = 0, j = 0;
    unsigned char str[32];

    do
    {
    backstr[i++] = (num % 10) + '0';
    num /= 10;
    }
    while(num);

    do
    {
    str[j++] = backstr[--i];
    }
    while(i);

    str[j] = '\0';
    kprint(attribute, str);
}




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值