903-输入输出的控制方式
# 903-输入输出的控制方式
那现在看来,跟外界交互也没有那么复杂嘛。 跟以前与存储器的交互差不了多少。我给一个地址,得到一个数, 或者给一个地址,写进去一个数,这样就跟外设进行交互了。 那这么说也不是不对,最简单的情况确实是这样的。 那我们也不妨从这最简单情况开始说起吧。
CPU控制外设进行输入输出的方式主要有三种。 第一种叫做程序控制方式,第二种叫做中断控制方式,第三种叫做直接存储器访问方式。
# 程序控制方式
那我们先来看第一种程序控制方式。 我们还是用这个并行接口作为例子,来讲解程序控制方式是如何工作的。 程序控制方式,顾名思义, 其数据传送都是在程序的控制下进行的。 那这个方式又有两种具体的形式,
第一种成为无条件传送方式,这种方式适合于简单外设的操作。 我们假设外设始终处于准备好的状态,直接编写输入输出指令进行传送数据就可以了。 这样编写出来的控制程序可以非常的简单。
那像拨码开关、数码管,都是这样的简单外设,适合采用无条件传送的方式,比如要控制数码管这样的设备,我们只用在程序中简单写一个out指令, 把想要点亮的数码管的对应的比特置一。 而并行接口则会将这个数直接放到并行数据输出线上, 那这次传送就完成了。同样,如果要进行输入, 因为这些拨码开关连接到了并行接口的数据输入寄存器, 所以CPU只需要简单写一个in指令, 从数据输入寄存器这个端口读入数据,就可以得到当前拨码开关的值。
但是对于稍微复杂一点的设备,这样的方式就不适用了。 我们就得采用程序控制方式当中的另一种,叫做程序查询传送方式。
# 程序查询传送方式
在这种方式下,我们先得编写一段程序,用来查询外设的工作状态。 在确定外设已经准备就绪的时候,才进行数据的传送。 我们以打印机和扫描仪这样的设备为例, 这些设备也是可以连接在并行接口上的,但是除了刚才提到的那八位并行数据线,还应该有两根信号线来标明发送方和接收方是否已经准备好。 对于输入设备和输出设备都是如此。 那这对用于交互联络的信号,就叫做握手信号。 在数据传输的每一步,都需要通过握手信号进行确认,然后才可以进行下一步的传输。
那我们先通过数据输出的过程,来看一看程序查询方式是怎么工作的。 现在CPU通过系统总线连到了并行接口, 而并行接口的外面连接了一个输出设备,可以是一个打印机。
那我们现在要编写一段程序,希望在打印机上打印出一段文字。 那首先CPU要执行out指令,去写接口当中的控制寄存器。 控制寄存器当中由若干个位域组成,这些位域有着不同的含义,通常是用来设置这个并行接口的工作模式。 比如说接口的时钟频率应该是多少,对外的接口信号是高电频有效,还是低电频有效。 那我们要写进控制寄存器的这个数值,常被称作控制字。 那在通常情况下,在初始化的时候写入一次控制字就可以了。然后这个接口就会按照这样设置的工作模式一直工作下去。 除非要改变工作模式,才需要重新写入控制字。
那好,现在设置好了工作模式,我们就可以正式开始传输了。 那么在这段程序里面,接下来要写一个out指令, 将我们要打印的数据传送到这个接口的输出缓冲寄存器中。 那当这条out指令执行完之后,并行接口的硬件电路就会将输出缓冲寄存器当中的内容送到并行数据输出信号线上, 并且会将输出准备好信号置为有效。 而对于这个打印机外设来说,它一直在监测 “输出准备好” 这根信号。
一旦发现这根信号有效,就会从并行数据输出信号上采样数据, (peterjxl注 然后打印,打印完后告知CPU打印完了)然后将输出回答信号置为有效,表示它已经接收到了这个数据。 这个数据可能表示一个字符, 那现在打印机就可以把这个字符打印在纸上了。
我们要注意,在这种情况下,这个握手信号是必须的,因为打印机这样的外设,单纯看并行数据输出这组信号,并不能判断当前是否来了数据。 因为这组数据线即使是全0,也可能是有含义的。所以必须要等到并行接口发出了这个输出准备好信号,它才会去采样,而且只采样一次。
在打印机将输出回答信号置为有效后,它又处于等待状态。 那这个并行接口芯片发现输出回答信号有效之后, 就会让状态寄存器当中的某一位置为有效。 这个状态位叫做输出缓冲空,表示当前输出缓冲寄存器中已经没有需要发送的数据了。
而在刚才的这个过程当中,CPU实际上还在反复的执行指令,不断的从状态寄存器这个端口中,把数据读出来。 那么从状态寄存器当中读出的这个数,就称为状态字。 因为现在这段程序是在做数据输出,所以CPU读出状态字之后, 就会检查当前的这个状态字中输出缓冲空,这个状态位是否是有效的。 如果无效,那就再执行一次in指令,继续读状态寄存器。(peterjxl注:CPU一直等打印机打印完了,发出好了的信号后,才继续发送要打印的数据)
所以我们可以想像,这段程序应该是一条in指令。 然后是几条逻辑运算指令,去检查对应的状态位是否有效。然后是一条条件转移指令, 决定是否要跳回去继续执行那条硬指令。 那么直到有一次读出来的状态字中输出缓冲空这个状态位是有效的, 那CPU就会将下一个要打印的字符,用out指令送到并行接口的输出缓冲寄存器当中去,然后开始下一轮的输出过程。 这样不断的执行,打印机就可以打出很多的文字来了。
# 程序查询数据输入
那我们再来看一个数据输入的过程。 我们可以假象这个外设是一个扫描仪。那我们现在启动一个控制扫描仪的程序, 那同样在初始化时,CPU会执行out指令,将控制字写入接口的控制寄存器当中,设置好这个并行接口的工作模式。 然后我们操作这个扫描仪开始工作。 那扫描仪可能扫完了一张图片,但是先要存在扫描仪内部的缓冲区当中。 然后将其中第一个字节放到并行数据输入信号线上, 然后将输入准备好信号置为有效。
而并行接口的硬件一直在检查输入准备好信号是否有效。 一旦发现这根信号有效,就会采样并行数据输入信号线上的内容,然后放入输入缓冲寄存器当中,同时将输入回答信号置为有效,这个信号是告诉外设先不要传送新的数据。因为我们现在设计的这个并行接口,它的输入缓冲寄存器只有一个字节,所以一次只能接收一个字符。
如果是更为先进的并行接口,这个输入缓冲可能会更大一些,这样一次就可以接收更多的数据。 那我们现在还是只接收了这一个字节。
接收完之后,接口还是需要将状态寄存器当中输入缓冲满这个状态位置为有效。而在这个过程中, CPU应该一直在执行一段循环代码,从状态寄存器当中不断的读出状态字, 然后检查输入缓冲满这个状态位是否有效。 一旦发现这个状态位有效,就会继续执行后面的指令。 那后面就应该是一条in指令,从输入缓冲寄存器这个端口读入数据。 这就是从扫描仪传过来的第一个字符。
一旦CPU将这个数据读走了,那并行接口电路就会将输入回答信号置为无效,等待外设输入新的数据。 当然同时也会将状态寄存器当中输入缓冲满这个状态位置为无效。
那在这个过程中,扫描仪一直在监测输入回答这个信号。一旦发现无效了, 它就将它自己内部缓冲区当中的第二个字符,送到并行数据输入上。 同时再次将输入准备好信号置为有效, 这样就开始了第二个字符的传输工作。如此往复,就可以完成很多数据的传输。
# 程序控制方式的优缺点
那我们再来看一看程序控制方式的优缺点。 其中的无条件传送方式,优点是要编写的控制程序非常的简单。 但缺点是只适用于非常简单的外设的操作。 像打印机这种还不算太复杂的设备,就已经不适用了。而程序查询传送方式, 由于有了握手的过程,比无条件传送方式准确和可靠。 但它的缺点是查询外设状态占用了大量的时间。
那这两种方式还有一些共同的特点。 它的优点在于对外设的要求比较低,不需要外设在接口上有很复杂的功能。 而且控制程序的操作流程非常的清晰。
但是缺点在于,要靠CPU进行数据的传送, 如果要传送的数据量很大,除了查询外设状态花的时间之外,一个一个传送数据也需要花费大量的时间, 占用了CPU非常宝贵的运算资源,从而可能影响这个计算机系统的性能。
程序控制方式确实简单易行, 那对于出门开关一个小灯泡这样的事情,应该是没有问题的。 但是如果稍微复杂一些的情况呢,比如说我定了一个外卖,要送一份午餐过来。 那我不知道它什么时候才能送到,那我们如果用程序控制的方式, 比如说用无条件传送的方式, 那我在看的这个书,做一条条运算的之后呢, 突然一条写的,去校门口把这个外卖拿回来。 我就放下本,我去了,到了校门口, 不管是什么东西,看见就拿,啪,给拿回来了。 然后拿回来以后呢,不管是什么张嘴就吃,就把这当午餐给吃了,这恐怕不太合适,对吧,肯定会出问题。
所以那我们用程序查询模式呢, 那么就是这样。好,我们做的运算。这个要去拿外卖了,然后就说,诶,去校门口看一眼, 有没有外卖,好我就去了。校门口一看,哎呀没有,回来了。 然后写着,那个再去校门口看一眼,好放下,再去校门口看一眼,没有再回来。 一直在做这个循****环,一直放、看、没有、看、没有。然后直到又一次,看到有了,就把这个盒饭拿回来,就可以吃上这顿午饭了。饭虽然是吃上了, 但是这事儿恐怕就干不成了,这一整天,啥也没干,就光顾等这饭了。 所以这个方式呢,看来还是不太实用, 我们还得想新的办法。