Gos —— 你好啊,显示器

文章目录

  • IO接口
    • IO端口
  • 显卡
    • 显卡交互
  • 控制显示器
  • 参考文献

写在前面:自制操作系统Gos 第二章第三篇:主要内容是如何操纵外设,如何操纵显示器

IO接口

其实博主之前对和硬件打交道是非常恐惧的。一个是不了解,一个是外部设备种类繁多、原理各异,实在是没有太多的精力精通每一项了。其实,说白了就是没有一个统一的接口供我这种懒狗调用,兼容性太差。

但是,按照计算机哲学来看:任何不兼容的问题,其实都可以通过加一层来解决这个问题,这一层就是 —— IO接口。比如说,声卡就是驱动影响设备的;显卡就是驱动显示器的。所以,今天我们打交道的主要对象就是显卡了,通过显卡间接操作显示器。


什么是IO接口呢?
IO接口时连接CPU和外部设备的逻辑控制部件,其分为硬件和软件两个部分。硬件部分所做的都是一些实质具体的工作,其功能时协调CPU和外设之间的种种不匹配,如双方由于不匹配,那IO接口就实现数据缓存以减少等待时间;数据格式不匹配,那IO接口就可以负责数据转换的功能。
当然,IO接口的作用还有很多,总结如下:

  • 设置数据缓冲,解决CPU和外设速度不匹配的问题
  • 设置信号电平转换电路。CPU时TTL电平,而外设大多时机电设备,需要进行转换
  • 设置数据格式转换
  • 设置时序控制电路来同步CPU和外部设备
  • 提供地址译码

同一时刻,CPU只能和一个IO接口通信,当很多的IO接口同时想和CPU对话的时候。其实就导致了冲突的问题,那么如何解决呢?这个时候,我们再加一层去仲裁这个问题。而这一层就是大名鼎鼎的南桥

CPU通过内部总线连接到南桥芯片的内部。同时,在南桥内部集成了一些IO接口。除了集成之外,还有一些供其他非必要设备支持的PCI接口。
Gos —— 你好啊,显示器_第1张图片

IO端口

IO接口在诞生之初,其就被设置为通过寄存器来和CPU交互。其内部也有专门的寄存器用于数据交互,称之为端口。IO接口是CPU和硬件的桥梁。一端是CPU,另一端是硬件。端口是IO接口开放给CPU的接口,一般的IO接口都有一组端口,而每个端口都有自己的用途。

刚刚也说了,端口的本质就是寄存器,其也有自己的数据宽度。所以我们需要合适的指令去访问,那么怎么访问呢?

#Intel版本的汇编语言格式
操作码 目的 源

# 从端口读取数据 --> in
in al,dx	#dx☞端口号

# 写数据到端口 --> out
out dx,al	#dx☞端口号

显卡

某些IO接口也叫适配器,适配器是驱动某一外部设备的功能模块。显卡也称为显示适配器,不够其本质就是IO接口,起了个高大上的名字罢了,不要害怕。

显卡呢,是PCI设备,其就是插在上面那个图中的插槽的。


PCI总线时并行架构,并行数据需要保证数据发送之后要同时到达目的地。否则就是一团乱麻。为了解决这个问题,其实就不得不采用一次一位这样的发送方式,而这也被称为串口显卡。有人说这样可能会很慢,但是其实也不一定。记住:速率=单次传送数据*频率

为了显示图像,我们就需要显示器。但是无论是什么牌子的显示器,其都是由显卡来控制的。无论是哪种显卡,它提供给我们的可编程接口都是一样的:IO端口和显存。所以,同学们大家不要对硬件交互过于恐惧。

显存是什么
显存是由显卡提供的,它是位于显卡内部的一块内存,所以称其为显存。

显卡的工作原理就是不断的读取显存,随后将其内容发送到显示器之中。所以,我们要做的工作就是往这块内存中不断写数据。写什么数据呢?

当然是一个约定啦,ASCII码,按照这个写就可以了:
Gos —— 你好啊,显示器_第2张图片

显卡交互

那么问题来了,我们知道要写什么了,那么怎么写到缓存里面呢?

我们先来看一些显存的地址分布:

起始 结束 大小 用途
C0000 C7FFF 32KB 显示适配器BIOS
B8000 BFFFF 32KB 用于文本模式显示适配器
B0000 B7FFF 32KB 用于黑白显示适配器
A0000 AFFFF 64KB 用于彩色显示适配器


这里的地址是实模式哦

我们实现文本模式就可以了。也就是往上面0xB8000 ~0xBFFFF 这个地址范围写数据咯。
那么一个屏幕可以显示多少个文本呢?一本来说屏幕显示是行数*列数。常用规格有80×25、40×25、80×43 等等。我们这里就默认的 80×25 就好了。

我们要注意一个问题:彩色字符是怎么实现的呢?
是的,即便在文本模式下面,也是可以打印彩色字符的。实现原理就是用两个字节表示一个字符,其中1个字节表示文本内容,一个字节表示文本属性。其内存布局如下:
Gos —— 你好啊,显示器_第3张图片
图示说的很明白我这里就不赘述了。
下图显示了RGB三原色不同组合的效果:

R G B 不高亮 高亮
0 0 0
0 0 1 浅蓝
0 1 0 绿 浅绿
0 1 1 浅青
1 0 0 浅红
1 0 1 品红 浅品红
1 1 0
1 1 1 亮白

所以说,我们要打印出黑底亮白字的效果就需要往显存写入:0000 1111,即0x0F

控制显示器

所以,我们现在已经了解所有原理的。我们可以上手写代码了:

; 显卡主引导程序
;
; LOADER_BASE_ADDR equ 0xA000
; LOADER_START_ADDR equ 0x2

SECTION MBR vstart=0x7c00
    mov ax,cs           ;初始化
    mov ds,ax
    mov es,ax
    mov ss,ax
    mov sp,0x7c00
    mov ax,0xb800       ;0xb800 段基址
    mov gs,ax

; 清屏利用0x06号功能,上卷全部行,进行清屏
; int 0x10  功能号:0x60    功能描述:上卷窗口
; 输入:
; AH 功能号: 0x06
; AL = 上卷的行数(0代表全部)
; BH = 上卷的行属性
; (CL,CH) = 窗口左上角(x,y) 的位置
; (DL,DH) = 窗口右下角(x,y)的位置
; 无返回值!
    mov ax,0600h
    mov bx,0700h
    mov cx,0        ;左上角(0,0)
    mov dx,0x184f   ;右下角(80,25)
                    ;VAG文本模式中,一行只能容纳80个字符,总共25行
                    ;下标从0开始,所以0x18=24,0x4f=79
    int 10h
; 以下是操纵显示器打印字符
    mov byte [gs:0x00],'h'
    mov byte [gs:0x01],0x0F     ;黑底亮白不闪烁

    mov byte [gs:0x02],'e'
    mov byte [gs:0x03],0x0F

    mov byte [gs:0x04],'l'
    mov byte [gs:0x05],0x0F

    mov byte [gs:0x06],'l'
    mov byte [gs:0x07],0x0F

    mov byte [gs:0x08],'o'
    mov byte [gs:0x09],0x0F

    mov byte [gs:0x0a],','
    mov byte [gs:0x0b],0x0F

    mov byte [gs:0x0c],'G'
    mov byte [gs:0x0d],0x0F

    mov byte [gs:0x0e],'o'
    mov byte [gs:0x0f],0x0F

    mov byte [gs:0x10],'s'
    mov byte [gs:0x11],0x0F

    mov byte [gs:0x12],'!'
    mov byte [gs:0x13],0x0F

    jmp $

    times 510-($-$$) db 0	;总共512字节,需要有510个占位
    db 0x55,0xaa

很简单的汇编代码,做的事情也都写到注释里面了,起始也就是对MBR的代码的更改了一下。我们直接来看一下效果:
Gos —— 你好啊,显示器_第4张图片

参考文献

[1] 操作系统真相还原
[2] 百度图片

你可能感兴趣的:(GOS,stm32,汇编,显存,显示器)