3.输入输出结构
第三章/第七章:输入/输出结构
总线结构:
计算机内部的设备诸如处理器,IO设备(键盘,鼠标等),存储器等通过总线连接起来,总线一般由三种线组成:
-
地址总线:
前面提到过存储器单元都有自己的地址编号,对于IO设备的寄存器也有相应的地址编号,如果将两者的地址编号排列在一起,那么计算机中所有的数据单元都位于同一个地址空间(这样的说法可能有些抽象,但实际上就是所有的内存单元都有一个独一无二的编号,而这些地址编号按顺序排列就组成了地址空间),这样处理器只需要访问的数据的地址,放在数据总线上,总线上的设备的地址译码器会根据地址总线上的数据来判断处理器是否要访问自己,进而响应控制总线和数据总线。
地址总线的位宽(就是一次传输数据的位数)决定了处理器的最大寻址空间,一般计算机的地址总线的位宽为32或者64,比如32位的地址总线最大的寻址空间为
2的32次方
也就是4GB
的空间大小。这意味着处理器主存大小最大为4GB(注意不是内存的大小,因为处理器不直接和磁盘等辅助存储器交互)
- 控制总线:控制总线用于传递计算机发出的指令,它的位宽不固定,一般有处理器的架构和总线协议决定,同时控制总线中还包函时钟总线,用于同步整个总线上的各个设备。
- 数据总线:数据总线用于处理器和总线上的设备间的数据传输,它的位宽为16,32,64,通常和处理器的字长相同。当一个设备接收到读的指令时,就会将地址总线上的地址处的数据写入数据总线,从而将数据传递给处理器。
IO设备的接口:
如上图,IO设备通过接口接入总线,接口一般由下面三个部分组成:
- 寄存器:IO设备的寄存器被映射到处理器寻址的空间当中,可以被处理器通过地址总线访问,通常由三种寄存器组成
- 数据寄存器:用于存放接收到的或者要发送的数据
- 状态寄存器:不同位的值代表着IO设备的各种状态
- 控制寄存器:不同位的值控制着IO设备的工作模式
- 控制电路:读取控制总线上处理器发出的指令,执行相应的操作。
- 地址译码器:读取地址总线上的地址编号,判断处理器是否是在访问自己。
通过上述的接口结构,处理器只需要通过不断读取IO设备的状态寄存器,当状态寄存器里的值反映出数据寄存器存在数值,需要处理器进行读取时,处理器就会通过控制总线发送读取数据寄存器的命令,进而IO设备的控制电路会根据命令将数据寄存器中的数据放上数据总线将数据发送给处理器,这就是IO设备和处理器交互的过程。
IO设备的中断:
但是上面的这个过程存在过度占用处理器的问题——需要处理器不断地去读状态寄存器。如果IO设备上长时间上都没有数据输入,那么处理器一直在这里耗着这就是极大的浪费,因此这个时候就考虑使用中断来解决这个问题。
当使用中断时,处理器不必一直轮询IO设备的状态寄存器,而可以一直执行其它事情,当IO设备有数据输入的时候,发送一个称为中断请求的硬件信号给处理器(硬件信号的产生通常由特定事件造成的,比如当数据寄存器被填满这个事件发生时,IO设备就会发送数据读区中断的信号),让处理器停下手头的工作去执行中断处理函数(在这里就是读取IO设备的数据寄存器)。
一个很重要的地方就是中断请求信号必须向处理器表明是哪个设备申请的中断,这在有多个可以请求中断的设备是十分必要,否则处理器又要取挨个轮询每一个设备状态寄存器的IRQ位(这一位在设备发出中断请求后被置为1)来确定是谁发出的中断,如果同时有多个中断请求时,处理器也只会执行轮询到的第一个IRQ位为1的设备的中断服务函数。当中断请求信号可以表明自己是哪个设备发出的时,上述的问题都得到了解决,并且如果同时有两个中断请求,也可以根据事先对设备设置的优先级来决定哪个中断请求先被响应。
还有一个问题就是处理器如何根据不同设备的中断信号来判断该执行哪一个中断服务函数。这个过程通常是处理器通过查表来解决的,这个表就是中断向量表。中断向量表是由中断向量组成的,每一个中断向量都是一个指向对应中断服务函数的函数指针,当处理器接受到中断请求时它会进行查表,找到对应的中断向量,从而执行对应的中断服务函数。而这个表通常存放在存储器分配的一个永久的区域内。(在Stm32单片机中这个表写在启动文件中)
在IO设备的控制寄存器中应该有一位用来设置是否开启中断,处理器中也有专门的控制寄存器用来设置是否接收中断。值得注意的是中断实际上十分类似之前提到过的子程序的调用,它也是允许中断嵌套的。中断还有许多细节这里就不再过多阐述了。
总线仲裁:
当两个主控设备想要同时使用总线访问相同资源时就会有总线冲突,这时候就需要由总裁电路决定哪个设备先使用总线——这个过程就是总线仲裁。
仲裁链路的结构如下:
每个设备与仲裁连接两根数据线——请求线和授权线,当两个设备同时向仲裁电路通过请求线发送总线的使用请求时,仲裁电路通过优先级判定哪个设备优先使用总线,并通过授权线允许设备使用总线,从而完成总线仲裁。