文章插图
大家都知道我们可以使用C语言写一段程序来控制硬件工作,但你知道其工作原理吗?
1c语言在实际运行中,都是以汇编指令的方式运行的,由编译器把C语言编译成汇编指令,CPU直接执行汇编指令 。
所以这个问题就变成,汇编指令是如何操作硬件的?
如果把硬件平台限制在x86环境下,那么汇编指令操作硬件基本上只有两种方式:
方式一:
通过向内存空间写数据 。硬件会把硬件上的各种寄存器(外行可以理解为访问硬件的接口或者操作硬件的工具)映射到某一块内存地址空间上,之后只要用汇编指令,甚至C语言去读写这一段内存地址空间(并非真正操作物理内存),就可以达到操作硬件的目的了 。
如果题主还有windowsXP环境(虚拟机也可以),就可以用汇编指令直接操作显存:
MOV AX,B800
MOV ES,AX
XOR DI,DI
MOV CX,0800
MOV AX,5555
REPZ STOSB
硬件的各种寄存器会被映射到某一块物理内存中,这种方式称为MMIO,在Windows的设备管理器里,右键点设备,看属性-》资源里,不少硬件设备都有“内存范围”的参数,这里的内存范围就表示这个硬件的资源可以通过访问这一段内存来控制它 。
方式二:
x86汇编中,还有两个特殊的指令是IN和OUT,这是x86平台独有的,上面图里的I/O范围,就是用IN/OUT这两个指令来访问和控制的 。
以上两种访问硬件的方式,第一种是可以用C语言实现的,上面一段汇编,本质上类似于C语言代码:
char ptr = 0xB8000;
int i;
for (i = 0; i 《0x800; i++)
{ptr + i = 0x55;
}
第二种IN/OUT方式没有直接的C语言语法对应,需要自己封装汇编 。
那么为什么平时很难用C语言操作硬件呢?这是因为平时写的代码大多数都在保护模式下,保护模式下,直接访问物理地址会受到限制,C语言操作的地址都是虚地址 。
对于Windows来说,要访问物理地址,需要工作在内核模式,也就是的写驱动才行 。
而在显存方面,首先,题主要先明白物理地址和虚拟地址的概念 。
原来的8086cpu设计的时候,地址空间有一块区域(640K-1M)之间,有一块作为显存使用
这里你说的预留的地址,是指物理地址,这一段地址的准确范围是000A0000-000BFFFF,不管是32位还是64位CPU,这一段物理内存地址一直都保留给显存使用,不区分32位还是64位,也不区分保护模式还是实模式 。
可见这一段内存至今仍然是留给显卡使用的 。
那么现在为什么不能直接用这段内存了?
因为现在的软件都运行在保护模式下,访问的地址都是虚拟地址,而并非物理地址,包括你使用cmd命令打开的环境,都是虚拟地址,虽然32位XP里能用debug命令向000B8000上写数据并能显示在cmd的界面里,但本质上,这都是虚拟出来的 。
如果要想用这段显存怎么办?
自己写一个简易的操作系统,不启动显卡的各种图形加速功能,CPU进入保护模式后在GDT里映射一个4G的数据段,与物理地址一致,那么向000B8000上写数据,就会像过去DOS一样显示在屏幕上,所以保护模式下也可以访问这一段内存 。所以,保护模式下,也可以用它 。
显卡那么多显存是怎么映射的?
有很多内存地址被映射给显存了,就是通过这种映射关系,把一些物理地址留给显存,使得CPU能像访问内存一样访问显存资源 。
当然,实际情况是,2G显存未必完全映射,而是只映射一部分地址,显卡有一些开放的寄存器能够控制哪部分显存映射过来,这样就能使得CPU在使用比较少的物理地址范围的情况下,访问全部的显存 。
还有一个很有意思的事情:在虚拟机里,找到映射的高地址部分的第一块内存区域,写一个能直接访问物理地址的程序(比如一个驱动),去读这一块内存,然后写到文件里,再用屏幕截图,也写到文件里,会发现截图的内容和显存里读出来的内容基本上是一样的 。
21 语言层面上,C能直接操作的“硬件”只有内存地址 。虽然C支持register关键字,但是不能指定某个特定的寄存器,所以只有内存地址 。而C中操作内存地址的方式就是指针 。例如:
char p =。..;p =。..;
2 根据1反推,可以明白如果要开放给C来操作某个硬件,最直接的方案就是设计硬件的时候预先分配好一些固定的地址的用途,然后实际项目中往这些固定地址写入合法的数据 。这样就可以通过类似
推荐阅读
- 最通俗的语言讲清楚RPC和HTTP
- C语言中的最常用的两种排序算法你知道吗?
- C语言为什么需要头文件
- C语言的数据类型介绍
- Java语言 面试中八大常见排序算法
- 你知道C语言中的C是怎么来的吗?
- C语言的位级运算
- Go 语言机制之逃逸分析
- 3000左右电脑组装机配置推荐 电脑硬件价格查询
- 一图看懂编程语言迁移模式:终点站是Python、Go、JS