由于计算机游戏与内存和 I/O 有着非常密切的关系,因此,它们推动计算机达到其最大性能。善于游戏编程的程序员通常很了解视频和音频硬件,并会优化代码的硬件特性。
I/O 访问层次
应用程序通常从键盘和磁盘文件读取输入,而将输出写到显示器和文件中。完成 I/O 不需要直接访问硬件——相反,可以调用操作系统的函数。
与《虚拟机》一节中描述的虚拟机相似,I/O 也有不同的访问层次,主要有以下三个:
1) 高级语言函数
高级编程语言,如 C++ 或 Java,包含了执行输入输出的函数。由于这些函数要在各种不同的计算机系统中工作,并不依赖于任何一个操作系统,因此,这些函数具有可移植性。
2) 操作系统
程序员能够从被称为 API(应用程序编程接口,Application Programming Interface)的库中调用操作系统函数。操作系统提供高级操作,比如,向文件写入字符串,从键盘读取字符串,和分配内存块。
3) BIOS
基本输入输出系统是一组能够直接与硬件设备通信的低级子程序集合。BIOS 由计算机制造商安装并定制,以适应机器硬件。操作系统通常与 BIOS 通信。
设备驱动程序
设备驱动程序允许操作系统与硬件设备和系统 BIOS 直接通信。例如,设备驱动程序可能接收来自 OS 的请求来读取一些数据,而满足该请求的方法是,通过执行设备固件中的代码,用设备特有的方式来读取数据。
设备驱动程序有两种安装方法:一种是在特定硬件设备连接到系统之前,或者设备已连接并且识别之后。对于后一种方法,OS 识别设备名称和签名,然后在计算机上定位并安装设备驱动软件。
现在,通过展示应用程序在屏幕上显示字符串的过程,来了解 I/O 层次结构如下图所示。
该过程包含以下步骤:
1.应用程序调用 HLL 库函数,将字符串写入标准输出。
2.库函数(第 3 层)调用操作系统函数,传递一个字符串指针。
3.操作系统函数(第 2 层)用循环的方法调用 BIOS 子程序,向其传递每个字符的 ASCII 码和颜色。操作系统调用另一个 BIOS 子程序,将光标移动到屏幕的下一个位置上。
4.BIOS 子程序(第 1 层)接收一个字符,将其映射到一个特定的系统字体,并把该字符发送到与视频控制卡相连的硬件端口。
5.视频控制卡(第 0 层)为视频显示产生定时硬件信号,来控制光栅扫描并显示像素。
多层次编程
汇编语言程序在输入输出编程领域有着强大的能力和灵活性。它们可以从以下访问层次进行选择 (如下图所示):
第 3 层:调用库函数来执行通用文本 I/O 和基于文件的 I/O。
第 2 层:调用操作系统函数来执行通用文本 I/O 和基于文件的 I/O。如果 OS 使用了图形用户界面,它就能用与设备无关的方式来显示图形。
第 1 层:调用 BIOS 函数来控制设备具体特性,如颜色、图形、声音、键盘输入和底层磁盘 I/O。
第 0 层:从硬件端口发送和接收数据,对特定设备拥有绝对控制权。这个方式没有广泛用于各种硬件设备,因此不具可移植性。不同设备通常使用不同硬件端口,因此,程序代码必须根据每个设备的特定类型来进行定制。
如何进行权衡?控制与可移植性是最重要的。第 2 层(OS)工作在任何一个运行同样操作系统的计算机上。如果 I/O 设备缺少某些功能,那么 OS 将尽可能接近预期结果。第 2 层速度并不特别快,因为每个 I/O 调用在执行前,都必须经过好几个层次。
第 1 层(BIOS)在具有标准 BIOS 的所有系统上工作,但是在这些系统上不会产生同样的结果。例如,两台计算机可能会有不同分辨率的视频显示功能。在第 1 层上的程序员需要编写代码来检测用户的硬件设置,并调整输出格式来与之匹配。第 1 层的速度比第 2 层快,因为它与硬件之间只隔了一个层次。
第 0 层(硬件)与通用设备一起工作,如串行端口;或是与由知名厂商生产的特殊 I/O 设备一起工作。这个层次上的程序必须扩展它们的编码逻辑来处理 I/O 设备的变化。实模式的游戏程序就是最好的例子,因为它们常常需要取得计算机的控制权。第 0 层的程序执行速度与硬件一样快。
举个例子,假设要用音频控制设备来播放一个 WAV 文件。在 OS 层上,不需要了解已安装设备的类型,也不用关心设备卡的非标准特性。
在 BIOS 上,要查询声卡(通过其已安装的设备驱动软件),找出它是否属于某一类具有已知功能的声卡。在硬件层上,需要对 特定模式声卡的程序进行微调,以利用每个声卡的特性。
通用操作系统极少允许应用程序直接访问系统硬件,因为这样做会使得它几乎无法同时运行多个程序。相反,硬件只能由设备驱动程序按照严格控制的方式进行访问。
另一方面,专业设备的小型操作系统则常常直接与硬件相连。这样做是为了减少操作系统代码占用的内存空间,并且这些操作系统几乎总是一次只运行单个程序。Microsoft 最后一个允许程序直接访问硬件的操作系统是 MS-DOS,它一次只能运行一个程序。