这一篇是整理一下刚看到的第7章,第10章,主要是常用接口技术和8255A。中断系统由于众所周知的原因,先继续放着;8253下次整理。
在之前的讨论中,我们都集中在CPU与存储器(内存)上。我们很少讨论那些更广泛存在的设备(外设),例如打印机,鼠标,键盘,发光二极管。显然,CPU的运行速率比外设的处理速度要高得多,同时,外设的数据线和控制线也与CPU并不直接兼容。所以,CPU和外设通信必须借助必要的电路来实现,这也就是是之前介绍中出现的I/O接口。
CPU和外部设备通信,第一件事情一定是给外设分配唯一的地址。这里有两种方式,第一种是独立编址,即I/O端口的空间与原有的存储器空间独立,这样不用担心地址冲突。我们通过专门的指令来进行I/O的输入输出。8086/8088就是典型的独立编址,使用$\mathrm{M}/\overline{\mathrm{IO}}$来区分是进行存储器读写还是I/O读写。另一种就是统一编址,即占用存储器的一部分空间,这种的好处就是不需要设置专门的指令了。
确立了地址后,现在要考虑输入和输出的方式,有四种基本的方式:无条件传送方式,程序查询方式,I/O中断方式,DMA方式。它们的复杂程度依次上升,我们可以沿着这四种方法来体会“接口技术”的思想。
输入/输出的基本方式
首先,要复习一下三种基于三态门的芯片,它们也要背下来,因为考试会考连接芯片的题目,它不会进一步告知你这个芯片是干嘛的。
74LS244是一个单向的缓冲器,74LS245是双向的,它们都没有锁存的功能。只是通过引入三态门,让信号传送时不至于出现总线竞争。
74LS373是通过电平控制来锁存信号,74LS374是上升沿来锁存。
现在我们开始依次介绍,第一个是无条件传送,它之所以叫无条件,就是因为它只传送数据信息,不传送状态和控制信息。
左侧是输入端口,这里略去了端口地址译码,当CPU选中这个端口,且确认读I/O设备后,74LS244会允许导通,把数据传到数据总线上。
右侧是输出端口,这个以点亮发光二极管为例,这里的74LS273不用管它,它是一种通过CLK来进行清除的锁存器,没有三态功能,上升沿有效,在这个情景下可以理解为和74LS373一样。
这种无条件传送,需要满足“输入缓冲输出锁存”,因为输入时,如果不缓冲,会发生总线竞争。输出时,如果不锁存,由于外设较慢,数据总线上的数据可能会被覆盖掉。
所以这种方式,只适合很简单的情况,如果CPU在快速的输出一些数据,那用这个机制就会出大问题。例如,当打印机接口为“忙”时,如果还把数据传给打印机接口,会直接覆盖掉这些没有及时接收的数据,造成数据丢失。
这就引出了第二种方法,程序查询方式。道理很简单,我只需要等到打印机什么时候不忙了,我再把数据传给它,在这之前我等待就好了。输入的时候也是同理:
我们现在通过简单的示意电路来进一步理解这种方法,由于这种方法涉及到要知道此时外设的状态,所以CPU会执行一条指令(IN)获得此时设备的状态。我们先说输入,当输入设备准备好设备后,图中左下角的选通信号会被激活,然后数据锁存器会存入要输入的设备,同时D触发器Q端置1。
然后,CPU执行IN指令读取端口状态信息,此时激活了图下方(读状态)处的门1相与后,会使得旁边那个三态缓冲器打开,这样Q的高电平就会传入数据线上的$D_0$,这说明CPU知道此时外设已经READY了。
程序检测到此时外设READY了,再次执行IN,这时激活的是$\overline{\mathrm{CS}}_2$相连的那个门,经过门2输出低电平,这时数据缓冲器被打开,数据被上传到数据总线;同时D触发器被清零,外设的状态被重置。
实际上西电版教材删除了这部分内容,但我觉得这里把它们引入,可以将汇编与电路图联系在一起,例如,“程序查询方式”所谓的“程序”,我们这里就可以给出来:
1 | SPORT EQU 300H ;状态端口 |
输出时也类似,当CPU准备向外输出数据时,首先执行IN读取状态口的状态,此时门1处被激活,三态门开启,此时从数据总线的$D_1$中读入BUSY状态,BUSY=1说明外设忙,需要等到BUSY=0时再输入新的数据。
当BUSY=0以后,CPU执行OUT指令,此时门2激活,产生选通信号,一方面把数据存入锁存器,另一方面,选通信号的后沿(低电平转高电平,上升沿)使得D触发器的Q产生翻转(之前的BUSY是0,所以此时Q变成1,代表外设开始忙),等外设处理好以后,会送回一个应答信号$\overline{\mathrm{ACK}}$来将D触发器清零,此时Q为0,即置BUSY为0,允许CPU继续输出。
这样做的缺点是,如果我有多个外设,这种方法会很呆。假如我们真的使用这种方式,那么假如我在打字,我打字的速度肯定远慢于CPU的处理速度,这就导致绝大部分时间花在了检测键盘状态和等待上。如果我同时连个鼠标,那我该如何设定程序使得CPU什么时候检测鼠标的状态让我操作,什么时候检测键盘状态让我操作。也就是说这种方式不适合要求实时交互的场合,于是就有了第三种方式:I/O中断。
从这个地方引入,就能感受到为什么“中断概念是计算机技术的重大变革”。在我们刚才的场景中,如果引入了中断,CPU将不需要原地踏步般的查询I/O状态。只有当输入设备准备好数据,或者输出端口的数据已空时,才向CPU发中断请求,CPU响应中断后,暂停执行当前程序,完成中断服务,等中断程序完成后再回原来的程序。详情在中断那章(可能)会涉及到。
最后一种即DMA,在介绍8086的总线请求等指令那里遇到过,简单来说就是跳过CPU,由DMA控制器直接进行I/O,在这里我们仅作简单了解。
连连看
这一章到最后,有可能会有连接接口的连线题的,出的题会在5个微机系统以内:
系统 | 总线信号 |
---|---|
8086最小系统 | $\mathrm{A}_{15}\sim \mathrm{A}_0,\mathrm{D}_{15}\sim \mathrm{D}_8,\mathrm{D}_7\sim \mathrm{D}_0,\mathrm{M}/\overline{\mathrm{IO}},\overline{\mathrm{RD}},\overline{\mathrm{WR}},\overline{\mathrm{BHE}}$ |
8086最大系统 | $\mathrm{A}_{15}\sim \mathrm{A}_0,\mathrm{D}_{15}\sim \mathrm{D}_8,\mathrm{D}_7\sim \mathrm{D}_0,\overline{\mathrm{IOR}},\overline{\mathrm{IOW}},\overline{\mathrm{BHE}}$ |
8088最小系统 | $\mathrm{A}_{15}\sim \mathrm{A}_0,\mathrm{D}_7\sim \mathrm{D}_0,\mathrm{IO}/\overline{\mathrm{M}},\overline{\mathrm{RD}},\overline{\mathrm{WR}}$ |
8088最大系统 | $\mathrm{A}_{15}\sim \mathrm{A}_0,\mathrm{D}_7\sim \mathrm{D}_0,\overline{\mathrm{IOR}},\overline{\mathrm{IOW}}$ |
IBM PC/XT 系统 | $\mathrm{A}_{9}\sim \mathrm{A}_0,\mathrm{D}_7\sim \mathrm{D}_0,\overline{\mathrm{IOR}},\overline{\mathrm{IOW}},\mathrm{AEN}$ |
就算没有直接连接接口的题,上面5个系统也会出现在后面8253,8255A的应用题里。简单的一些例子即上面的无条件传输,其实只需要编一个译码电路。这里我记录一个书上比较复杂的例子。(其实在8086里还要注意奇偶地址的事情,但是我写的时候我忘了……这个在后面连那俩可编程芯片时还会提到)
这是某一输出设备的工作时序图,当它不忙时,状态信号BUSY=0,CPU可以向外输出,当数据加到外设上时,必须利用$\overline{\mathrm{STB}}$将数据锁存于外设,饼命令外设接收数据。设数据输出端口地址为02F8H,命令输出端口地址为02F9H,状态输入端口为02FAH。
(1)将该外设连接到8088最大系统上;
(2)编程实现将内存40000H开始的连续50个字节单元的数据,利用查询发输出给该设备;
我们可以think step by step…如果直接看书上的答案,第一时间会有些头大。
第一步,我们先分析给定的地址,02F8H,02F9H,02FAH,即0000 0010 1111 1xxx,仅有后三位8,9,A的不同(000, 001, 010)。所以我们可以选用一个74LS138来译码。我们让固定的那些地址位作为使能端。
第二步,在程序查询式的方式中,我们需要考虑一些电路的设置。首先是一个锁存器,这个锁存器要将数据输出到设备上。这里选用74LS273,显然,这个锁存器的使能端需要在02F8H时激活,这个部分需要当CPU发出写入的指令时,即$\overline{\mathrm{IOW}}$,所以我们将74LS138的$\overline{\mathrm{Y}}_0$与$\overline{\mathrm{IOW}}$相或。
第三步,除了锁存器,BUSY还需要向CPU输入外设此时的状态,输入时需要一个缓冲器,这里用74LS244(其实只用到了它的一个端口),缓冲器的输出会送入数据总线,这里送入了$D_7$。最后我们考虑74LS244的使能端,首先这是状态的输入端口,所以和02FAH相关,这个状态是当CPU发出IN指令,$\overline{\mathrm{IOR}}$低电平有效时发出的,这样就完成了74LS244的这个部分。
第四步,最后还缺一步命令输出,“输入缓冲输出锁存”,此时我们仍需要一个锁存器,继续用74LS273,这里只用它的一位(就$D_0$了,只要和刚才的$D_7$不冲突即可),这个锁存器的使能端与02F9H相关,输出时是将$D_0$给输出进外设,所以此时$\overline{\mathrm{IOW}}$是低电平。这样就完成了线路的连接。
与之前的三态门的芯片不同,由于这里74LS273没有三态的功能,更新是靠CP(CLK)实现的。每次上升沿,数据会通过芯片;为0时,数据锁存。这其实并不影响连线。当我们沿着整个过程来理解时,我们会发现这里选用74LS273的原因:更稳定。
我们写出问题(2)的答案,将内存40000H开始的连续50个字节单元的数据,利用程序查询法输出:
1 | MOV AX,4000H |
注意,DX其实是作寄存器间接寻址,而IN和OUT里并不像MOV一样把寄存器“括起来”,因为IN和OUT的功能只能是间接寻址,所以习惯上就不加了。
上面的那个例题有些复杂了,考试时一般不会出成这样。可能会出一个淳朴的应用形式的题,例如:
有一台硬币兑换机,平时等待纸币输入,当硬件检测到有效输入时,会给状态端口(端口地址为FAH)$D_2$位置1,并在数据输入端口(端口地址为FCH)给出纸币类型,01H代表1元,05H代表5元,10H代表10元,20H代表20元。若兑换机硬币输出系统准备就绪,则状态端口$D_3$位由硬件置1,然后将兑换的5角硬币数送到数据输出端口(端口地址为FEH),硬币输出系统根据硬币数来输出硬币完成兑换。编写程序完成以上要求。
1 | START: |
并行接口芯片8255A
显然,在实际操作中,我们不可能一个电路一个电路的去构造接口。我们希望一些即插即用的方式,并且具有良好的封装。8255A就是这个东西,它是一个并行接口芯片,它可以取代上面的例子中的由74LS273,74LS244自己手搓出的电路。
然后,我们就被迫学(纸面上的)8255A的应用。
我们将整个芯片看作一个整体,只关心输入输出。8255A有四个8位寄存器。其中有三个数据寄存器A,B,C。我们称其为端口(port),所以引脚记作了$PA,PB,PC$。在这里,A和C的高4位为一组,B和C的低4位为一组,即A组和B组。
先放下“组”的那个概念,左下角的$A_0,A_1$,2位可以编码4个选项:
$A_1A_0$ | 端口 |
---|---|
00 | A |
01 | B |
10 | C |
11 | 控制寄存器 |
上面的控制寄存器,即“可编程”的来源。控制寄存器的8位,在后面的应用里很重要,因为我们要写出这8位的数字。这种控制可编程的“开关”叫作“控制字”,这里分为两种:方式控制字,置位控制字。
方式控制字时:
位 | 作用 |
---|---|
$D_7$ | 方式控制字时为1 |
$D_6D_5$ | 控制“A组”的工作方式,00为方式0,01为方式1,1x为方式2 |
$D_4$ | 端口A的方向 |
$D_3$ | 端口C高4位的方向 |
$D_2$ | 控制”B组”的工作方式,0为方式0,1为方式1 |
$D_1$ | 端口B的方向 |
$D_0$ | 端口C低4位的方向 |
写成一个竖式表格,可以一下子记住。最高位在控制方式是1时,是“方式控制字”,然后确定“A组”的工作方式,确定后依次是“A组”的构成:端口A和端口C的高4位的“方向”(方向是指,0为输出,1为输入);之后是“B组”的工作方式,然后是B组组成的方向。
置位控制字时:
位 | 作用 |
---|---|
$D_7$ | 位置控制字时为0 |
$D_6D_5D_4$ | 此时无意义,通常取0。 |
$D_3D_2D_1$ | 编码对应C口的$PC_7\sim PC_0$,如010指$PC_2$ |
$D_0$ | 0代表置0,1代表置1。 |
置位的意思是可以简单理解为,如果我们以C口作输出,C口控制8个开关,如果我们希望$PC_2$对应的开关闭合,其余状态不变。我们可以读入此时C口的端口信息,然后OR/AND,然后再OUT。有了置位控制字,我们可以直接操纵控制寄存器,来通过写入它实现置位与复位。
那么,什么是方式控制字里的“工作方式”呢?8255A有3种,0是基本的输入输出,1是有“联络”信号的输入输出,2是双向传送。我们一个一个来……
方式0时,对应之前的无条件传输。此时$D_0,D_1,D_3,D_4$决定各个端口的输入输出。例如$1\underset{A\text{组}}{\underbrace{00}}\underbrace{01}\underset{B\text{组}}{\underbrace{0}}\underbrace{10}$,这时,端口A与端口C的低4位是输出,端口B和端口C的高4位是输入。方式0其实可以理解为一个很好的封装的无条件传输,我们拉来一道标靶打一下:
某可编程逻辑电路构成的芯片可以完成16位数据的八选一功能,输入$x(i,j)$其中$(i\in0\sim7,j\in0\sim15)$,输出信号为$y(j)$,选择信号为$S_2,S_1,S_0$,真值表在下图。在IBM PC系统中开发一片8255A,端口地址为260H~263H,用于分时采集这8组16位数据(无符号数),找出当前数据的最大值,并通过C口的高三位(PC7~PC5)连接的LED灯指示其序号。连接下图的硬件电路(红色部分,我先连了,懒得仔细画了)并编写程序实现功能。
读完题,显然我们可以让A组和B组都是方式0,因为,这个神奇的8选1的外设,没有什么STB,BUSY之类的端口,方式0 is enough。
显然,我们可以用A口和B口来接收16位的数据,然后C口输出,其中高三位来点亮LED表示索引。一个思路是我们直接“打擂台”一样找最大值就好了。
1 | MOV DX,263H |
接下来是方式1,方式1是用来条件传输的。正如前面“程序查询式”中举的例子一样。在有条件时,我们需要关心外设的状态。而使用中断来进行接口之间交换,使得可以并行,在先前我们没能给出一个中断的例子,现在可以依靠8255A的封装,来初步理解一个(例子)。以及理解前面的“联络”。
我们以A口为例,在方式1下,外设把数据通过A口送给CPU的过程为:
①外设把数据送到$PA_7\sim PA_0$,使得选通信号$\overline{\mathrm{STBA}}$有效(A指port A,下同。STB指strobe,选通),数据进入A口的输入缓冲器。
②A口的IBFA有效(IBF指input buffer full,表示输入缓冲区满了),同之外设或CPU,表示A口接收了一个有效数据。
③A口的INTRA(interrupt)有效,以中断的方式通知CPU取走A口中的数据。
④CPU读A口,数据进入CPU。
⑤IBFA和INTRA转为无效。
注意,上图中还出现了一个INTEA,称为“中断允许”信号,我们会用置位控制字来让他为高电平,这样才能完成整个输入过程。
同理,在方式1下,CPU将数据通过A口送给外设的过程:
①CPU执行OUT,将数据写入A口的输出缓冲器。
②当有效数据进入A口的$PA_7\sim PA_0$时,$\overline{\mathrm{OBFA}}$有效(OBF是output buffer full),通知外设CPU已把一个有效数据传输给A口了。
③外设取走数据时,发$\overline{\mathrm{ACKA}}$信号(acknowledge,回执)给8255A,告诉A口外设正在取数据。
④A口$\overline{\mathrm{OBFA}}$无效,表示A口数据已被取走。
⑤INTRA有效,以中断方式通知CPU可以再输出数据给A口了。
实际上,上面的例子生动的站视了一个机制“握手”。通过“握手”信号,来协调数据的传输。“握手”信号至少要有两位信号线,其中一位由接口电路发给外设,另一位由外设发给接口。例如输入时的$\overline{\mathrm{STBA}}$和IBFA。$\overline{\mathrm{STBA}}$是外设所发,其有效时,通知接口A“我给了你一个数据”;IBFA是接口发出的,当其有效时,通知外设“你的数据我收到了”。在输出时,$\overline{\mathrm{OBFA}}$和$\overline{\mathrm{ACKA}}$也是一对握手信号,$\overline{\mathrm{OBFA}}$是接口发出的,当其有效时,通知外设“我这里有个新数据”,$\overline{\mathrm{ACKA}}$是外设所发,当其有效时,通知接口“我已经把你的新数据取走了”。这个机制对于复杂的外设,例如打印机,非常重要。
显然,在方式1中,接口C奉献了自我,充当了联络信号,这也是为什么置位控制字只针对C口的原因。应试角度上,我们得能分辨那一对握手信号谁是谁,以及理解前面①②③④⑤的过程(他们反应在汇编里就几行),而他们具体的$PC_x$可能没那么重要,因为题目会给(但最好还是背下来)。
(内心os:图丫丫!只有你能记住这串密码!)
最后用一道例题来给出,方式1是如何“影响”考试题的:
为了设计一个竞赛抢答系统,在8088最小方式系统中配置了一片8255A,用于CPU读取并显示人员编号。整个系统(如下图所示)的工作流程为:抢答器电路按照竞赛规则将抢答最快且有效的人员编号(共10人,编号为: 0~ 9)通过其数据引脚输出,同时输出数据准备好信号STB,编号数据在8255A的端口A锁存后由CPU读回,CPU识别编号后输出对应的段码,经8255A的端口B驱动数码管显示该编号。请完成:
(1)根据系统原理图,写出8255A的4个端口地址(未画出的地址线均为0)
(2)为满足系统设计要求,8255A的端口A和端口B应工作在哪种方式?
(3)已知数码管数据引脚a,b,c,d,ef,g,Dp依次连接8255A的PB0…PB7,请写出编号0~9对应的段码数据,并编写程序实现该系统的功能。
先读图,会发现地址是0000 0100 1010 00xx,即端口地址为04A0H,041H,042H,043H。注意$PC_4,PC_5$,可以看到A组是方式1输入,B组是方式0输出。
然后是显示数码管,比如数字0需要a,b,c,d,e,f亮起,他们对应$PB_0,…,PB_6$,所以是1100 0000,即C0H。原因是这个抢答器外接了一个Vcc,所以可以推测是PB低电平有效(产生电势差),以及这里的Dp是控制端的意思,那么按照共阳数码管的原理,Dp是高电平有效。所以段码数据为
数字 | 断码 |
---|---|
0 | 1100 0000 = C0H |
1 | 1111 1001 = F9H |
2 | 1010 0100 = A4H |
3 | 1011 0000 = B0H |
4 | 1001 1001 = 99H |
5 | 1001 0010 = 92H |
6 | 1000 0010 = 82H |
7 | 1111 1000 = F8H |
8 | 1000 0000 = 80H |
9 | 1001 0000 = 90H |
现在就可以写代码了:
1 | BUF DB C0H, F9H, A4H, B0H, 99H, 92H, 82H, F8H, 80H, 90H |
所以我们可以发现,这个功能在汇编里,只要求我们多一个检查C口的某一位是否有效。
最后,至于方式2。方式2可以允许两台处理机之间双向通信,那样的电路比较复杂,超出了考试范围。我看了西电教材这一章后面所有的习题,大部分都是方式0和方式1,所以,方式2就跳了。
还有最后一点,即8255A如何与CPU正确连接,在前面的例题里我们没有关注这个事情,这里有两个小的注意事项。
如果是8086,其最小方式和最大方式,区别只是读写信号的名字。真正要注意的是,如果8086采用奇地址,需将$A_0$换成$\overline{\mathrm{BHE}}$,并将数据总线从$D_7\sim D_0$换成$D_{15}\sim D_8$。如果是在IBM PC系统中,其采用的是8088最大方式,由于其系统包含了DMA,因此需要保证AEN=0。
End
本来,是想和8253一块整理的,后来发现,这个一章要记的太多了。快开学了,希望一切顺利,毕竟现在能做的已经很有限了。要是一年前做,大概就来得及了。不过,谁知道呢?