这说法完美,不过上面还有个问题,就是像键盘这样的还好,因为它确实需要执行一段特殊的驱动程序去完成功能。但想磁盘这种,单纯的就是读出数据写到内存或者读内存数据写到磁盘,这种操作很低级但是很耗时间,如果每次都是通过中断然后数据通过cpu先传到寄存器在一个个传到内存,那就让cpu太大材小用了。这种重复的耗时的劳动,最好别占用cpu,直接从硬盘通过某个设备到内存就好了,这个设备就叫做IO控制器DMA。硬盘接收到cpu的读请求后,向dma发请求信号。dma完成了从硬盘写入内存操作后,再向cpu发一个中断信号,简单执行一下数据处理完的中断程序就行了,至于数据传输的过程,cpu可以做其他更高级的事情。
完美,不过上面的又有一些问题,就是你虽然不占用我cpu时间,但你占用总线啊,我们是公用一条总线传输数据的,你传输数据占用总线的时候,我cpu就占不了了。或者你等我cpu不用总线的时候你在再用,这个叫做dma的时钟周期窃取。但这样也不好,我他妈就希望你离我越远越好,别占我cpu时间也别占我的地方,让专门一个可以执行简单指令的设备和你公用一条单独的总线去完成这件事,我称之为low版cpu,他就是io通道。
再说说IO端口地址问题,cpu如何指定一个端口呢,可以用一个部分表示地址,另一个部分表示是IO地址还是内存地址。还有一种方式是,将io端口也加入到内存一样的地址范围中,然后访问一个端口跟访问一个内存地址没什么差别。所以上述到就是IO端口的两种编址方式,第一种是独立编址,采用端口映射io,第二种是统一编制,采用内存映射io,现在基本都是内存映射。整个io这一块大体的骨架就是这样子的,你看刚刚所说的中断呀,dma呀这些,我觉得可以理解为操作系统,或者说由于使用cpu的需求倒逼出的产物。当然所有这些都可以用软件来实现,但当需求足够大的时候可以让cpu为操作系统做出一些改变的,这并不是cpu原本就是这个样子。其实上面提到的中断,是外部中断,当然也可以是内部中断,就是指令自己去出发一个中断。这是根据中断源的不同分的。当然本质是一样的,都是往一个寄存器或者几个寄存器里写数,cpu一个时钟周期专门查看一下这个寄存器,然后查下中断向量表找到对应的程序执行一下,执行完了恢复之前的pc再继续往下进行。
整个io差不多就是这样的骨架,所以你看为什么操作系统关注io,关注内存管理,关注多进程,因为没啥别的东西可关注了,cpu原本能做的事情太简单了,所谓操作系统也好,dma这些新增的硬件也好,没有什么技术上高端的事情,或者说在计算机底层,高端的本质就是复杂和麻烦。你说研究底层的人特别高端不如说它们对每个细节了解得足够全面,这些细碎的知识联系在一起本身就是足够高端的技术了,这也回答了我好久之前写过的一篇《究竟什么是技术》。你包括我的第一张74LS173的针脚图,如果你看了我说的什么“部件”巴拉巴拉明白了,你可以说你懂,当然你把cpu主要部件的针脚图都看了,都记住了并且在面包板或者焊接版上接过了,你也可以说你懂。但这层次就不同了,所谓理解得深不深,其实就在于细节。
再说说内存地址管理,或者说寻址方式,当然你可以在指令中的地址就表示绝对的地址,不经过任何转换直接到内存或者相应的设备中输入这个地址信号然后读数据。你或者把俩地址拼一块,形成一个新地址。再或者你形成新地址后再通过某种方式转换映射一下,或者再映射一下。等等,操作系统对内存的管理就是这些,全都是细节。我只是简单入了个门,最开始cpu是绝对地址寻址,就是我指令中的地址直接输入到某个部件的地址线上。第一个搞事情的是8086cpu,也就是x86架构的鼻祖cpu,它有16位数据线,但有20位地址线。当然你可以只用16位地址线但当时恰好人们觉得地址不够用了,然后又各种原因不能弄成32位的cpu,于是乎寻址的时候就把一个寄存器当作段地址数据,另一个当作段内地址,其实别管那么多,就是应给凑成了20位地址罢了,这样寻址范围就扩大了。但这设计好不好?美其名曰段地址和段内地址,其实这很麻烦,如果cpu位数够没人给自己找这种麻烦,以至于后来的32位cpu为了兼容以前的拍脑门设计,即便是寻址空间已经够了但还是采用这种段方式。但后来又说操作系统变得复杂了,倒逼着cpu弄出实模式和保护模式,每个段也有自己的权限呀长度呀等等各种标志了,这样段寄存器这样的设计就硬生生变得有用起来了,指向一张段表记录这些标志型的数据。