LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1345|回复: 14

如何实现汇编级的非阻塞I/O

[复制链接]
发表于 2004-6-1 23:59:30 | 显示全部楼层 |阅读模式
现在我们专业要做一个设计,在纯DOS下用x86 IBM汇编语言来编写一个串口通讯软件,双方互传各自键入的字符串。

我先分析一下。
一般来说,PC机可以通过三种汇编级方法来存取串口。
1.DOS中断调用
2.BIOS中断调用
3.直接驱动硬件(IN/OUT端口操作)
DOS调用不提供任何有关串口状态的反馈信息,而只是在串口上盲读写;直接驱动硬件过于繁琐;故考虑采用BIOS的INT 14H进行串口读写,它提供I/O位数据流给RS232串口。

问题是,因为BIOS中断调用是阻塞式I/O。

如何实现非阻塞I/O呢?
发表于 2004-6-2 01:07:36 | 显示全部楼层
直接操作串口控制芯片吧
我没用过
 楼主| 发表于 2004-6-2 01:10:56 | 显示全部楼层
补充一下直接驱动硬件这种方法。

使用IN/OUT端口I/O指令来编程8251A串口控制器以及8255A并口控制器(非阻塞键盘读取)即可实现非阻塞I/O且全双工串口通讯,但过程的确繁琐。

估计操作系统如Linux也是直接驱动这些I/O控制器来实现高级I/O功能的。
发表于 2004-6-2 08:11:50 | 显示全部楼层
最初由 home_king 发表

估计操作系统如Linux也是直接驱动这些I/O控制器来实现高级I/O功能的。

看看内核的源代码不就知道了。
 楼主| 发表于 2004-6-2 18:35:35 | 显示全部楼层
源码以前大致看过,宏封装的形式……,不大理解。

kj501大虾能介绍一下别的方法或者深入解释一下三种传统方法吗?
 楼主| 发表于 2004-6-2 18:42:26 | 显示全部楼层
再引申一个新问题。
如何查看x86系统的控制器(如8255A)的端口地址呢?访问BIOS数据区否?

ps:近来很多专业设计要同时干,所以有些问题难以抽空去实践,望各位帮帮忙讨论一下,谢谢。
发表于 2004-6-2 19:08:21 | 显示全部楼层
最初由 home_king 发表
再引申一个新问题。
如何查看x86系统的控制器(如8255A)的端口地址呢?访问BIOS数据区否?

ps:近来很多专业设计要同时干,所以有些问题难以抽空去实践,望各位帮帮忙讨论一下,谢谢。

x86体系结构的I/O地址是独立寻址的,只要知道地址,用in, out即可读取。
在网上找到这个,希望对你有所帮助:
http://home.zsu.edu.cn/caicomputer/ch6/ch6.htm
 楼主| 发表于 2004-6-11 23:52:34 | 显示全部楼层
最初由 kj501 发表
x86体系结构的I/O地址是独立寻址的,只要知道地址,用in, out即可读取。
在网上找到这个,希望对你有所帮助:
http://home.zsu.edu.cn/caicomputer/ch6/ch6.htm

思考了许久,还是不得其解。
给出三个汇编级串口编程的高级话题,考考大家。

1.究竟如何获知各类外设控制芯片的端口地址(除了查设备手册)呢?

2.BIOS利用x86架构的INT n提供的串口中断究竟与INTR外部串口中断有什么关联呢?我思考并多番实践过,两者的功能几乎等价。(可惜,后者我采用查询方式来"仿真"中断的并行效果,目前我还想不出如何利用INTR实现外部中断处理,请看第3问)

3.进一步,我如何编写我自己的串口中断服务程序呢?关键在于如何与INTR在中断服务程序的入口地址方面达成共识,也就是说,如何注册INT n。某教科书上曾提及过这话题,但并不详细,只是假设串口中断服务程序的入口地址为已知。奇怪。
发表于 2004-6-12 01:16:34 | 显示全部楼层
intel 听说要公开BIOS的源代码。弟兄有兴趣应关注!!!
PS:电子信息工程系 深入去搞硬件,是很前途的,,可怜偶N年前的机电一体化工程,拿到毕业证就把教科书丢掉,学VC。。DELPHI。。。唉。。

摆在墙角的示波器已被灰尘所淹没。。。
 楼主| 发表于 2004-6-12 08:53:28 | 显示全部楼层
嗯,查阅了一些资料。我就我的三个问题说说。(后两个问题基本解决)

8086的8259A可编程中断控制芯片有8级中断源,分别为IR0~IR7,可填写初始化命令字ICW2的高五位来决定它们各自的中断类型(低三位取决于中断请求从哪个IRx输入),它的端口地址为20H和21H(众所周知,x86架构的控制芯片都具有两个奇偶端口地址,对应不同的命令控制字以供初始化)。

IBM PC的惯例为

  1. [color=blue]中断源[/color]        [color=blue]中断类型号[/color]                [color=blue]中断功能[/color]
  2. IR0        08H                时钟定时器
  3. IR1        09H                键盘
  4. IR2        0AH                保留
  5. IR3        0BH                异步通信(COM2)
  6. IR4        0CH                异步通信(COM1)
  7. IR5        0DH                磁盘
  8. IR6        0EH                软盘
  9. IR7        0FH                并行打印机
复制代码

换言之,初始化ICW2命令字的指令为

  1. MOV  AL,00001000B
  2. OUT  21H,AL
复制代码


从中我们可以看出一些有趣的东西,BIOS提供的中断服务程序INT n中,n的取值功能对应关系与上表一致(从这个角度来观察BIOS,它一点都不神秘,它只是一段ROM程序罢了)。比如说,INT 9是BIOS键盘中断,恰恰对应了8259A的IR1中断源(也就是我们所熟悉的IRQ1)。

进一步说,如果要把BIOS例程替换为自己编写的中断服务程序,只要在中断向量表上的相应位置做手脚即可。中断向量表以4个字节为1个表项,保存了中断服务程序的CS:IP,共有256个表项。那么,我们把相应中断源的表项换成我们自己编写的中断服务程序的CS:IP即可。

举个实例吧。

假如现在有一台字符打印机,我们用自己的中断服务程序来驱动它。
8255A是8086的并行接口控制器,工作在方式1时,可支持CPU以中断方式与外设通信。将8255的PC3连接到8259A的IR3端,后者的中断类型号为0BH,0BH*4=002C(中断矢量表的入口地址=中断类型号*4);我们编写的服务程序入口地址为3200:0100H(使用ORG指令即可实现这点)。这样使用以下代码即可实现替换:

  1. MOV AX,0
  2. MOV ES,AX
  3. MOV AX,0100H
  4. MOV ES:[002CH],AX
  5. MOV AX,3200H
  6. MOV ES:[002EH],AX
复制代码


另外,再扩展一下话题,Linux内核中关于APIC(高级可编程中断控制器)的代码体现了这些东西,可以参考一下。


ps:至于端口地址的获取,除了查阅手册,估计别无它计。对于x86架构,估计这些也是固定值,问题不大。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表