前面讲到CPU通过三种总线与各类设备打交道,其中存储器是和CPU的地址、数据及控制总线相连,CPU将其看作一个逻辑内存空间。采用统一的编址方式。但是存储器芯片除了硬盘、内存条之外,还有一些接口卡如显卡、网卡等,这些设备上是自有内部芯片和内部寄存器,这些寄存器从CPU来看也是存储器的概念。在不同的系统架构中,如何确定这些寄存器,也就是如何对它们编址是不一样,在X86系统,引入一个新的编址空间叫端口,它与前面的内存地址空间隔开不一样,采用不同的指令。而在一些其它的如PPC等硬件架构中,它是采用统一内存地址空间。所以它们不存在端口概念。因此,在8086CPU中CPU可以读写如下3个地方的数据:CPU内部寄存器、内存单元、端口。在8086CPU中对端口定位是通过端口地址,因为端口所在的芯片是与CPU的三条总线相连,所以端口地址同内存地址一样,可以通过地址总线来传送,只是编址方式不同,CPU最多可以定位64KB的不同端口,范围是0~65535,并且端口的读写不能用mov push,pop等内存指令,而是使用in 和out指令。如下图所示:

image

如上图所示,in al,20h (从20h号端口读入一个字节),执行时首先CPU通过地址线找到in al,20h指令,通过数据线读入e420进入指令执行ALU中,ALU开始执行首先访问20H端口,接着通过控制线发出读命令,选中端口所在的芯片,并通知它读取数据,端口所在的芯片将20h端口中的数据61送入CPU的数据线,并最终到达al寄存器中。同样写也一样,如下图所示:

image

我们前面知道地址线宽度是20位,需要访问的端口号值是存放在寄存器中,因此端口号最大16位,如果大于8位使用dx中介。8086CPU有一个特殊规定就是只能使用ax或al来存放读入的数据或者要发送的数据。

image

这里需要注意的是不能直接数值写入端口如将8写入端口20h中,out 20h,8这种写法是错误的,需要先将8存入al中然后进行操作。

8086CPU还提供了一种移位的指令,这种指令同高级语言中移位操作符相似,分为左移与右移两种,左移一个8位会丢掉一个最左位,右移一个8位会丢掉一个最右位,这丢掉的存放在CF中。其中shl是逻辑左移指令,它的功能是1)将一个寄存器或内存单元中的数据向左移位;2)将最后移出的一位写入CF中;3)最低位用0补充。 mov al,01001000b shl al,1  执行后(al)=10010000b CF=0左移一位相当于*2。 如果要重复移位多次,将这些次数保存在cl中。同理shr 是逻辑右移。与shl操作相反。

image

image

注意,这里CF中存储只是最后一次操作中最后一次移出的一位。所以移动多位时如果中间有0或1丢掉,只取最后一次丢弃的值。上面的例子是以al作为示例的,实际上ax也可以如下图所示:

image

端口通常都是与外设相关,所以外设如I/O,CMOS都是有端口供CPU操作。其中CMOS RAM芯片在PC中一般用来掌管系统BIOS配置信息和时针信息。通常的CMOS 芯片包括一个实时钟(电池供电)和一个128存储单元的RAM存储器。在这个RAM存储器中0-0dh单元保存时间信息,其余保存系统配置信息,供系统启动时BIOS读取。另外这个芯片提供了两个端口70h和71h其中,70h为地址端口,存放在访问的CMOS RAM单元地址,71h为数据端口,存放从选定的CMOS RAM单元中读取的数据。CMOS中存储时间的值是用BCD码来表示,BCD码是另外一种码,不同于ANSI码,它是以4位二进制表示十进制数码表,但不是十六进制和二进制之间的转换,它只是用来表示十位数据符号的一种二进制表示,不存在值的真正意义上相同。类似于ANSI。如下图所示:

image

在CMOS中使用BCD码来表示两位十进制,如12月用BCD码是00010010,可以看出来一个十进制如4用BCD码表示是000001000b,而用ASCI表示则要加上30h成00110100b。下图是一个综合端口读写例子如下

image