• CPU的I/O能力

    接口芯片和端口

  • 外设通过接口芯片的端口和CPU交流

  • CPU在执行完当前指令后,可以检测到发送过来的中断信息,引发中断过程,处理外设输入。

    外中断信息

  • 外中断类型

    • 可屏蔽中断
    • 不可屏蔽中断
  • CPU是否响应可屏蔽中断看标志寄存器IF位的设置
    • IF=0,不响应可屏蔽中断
    • IF=1,CPU在执行完当前指令后响应中断,引发中断过程
  • 可屏蔽中断信息来自于CPU外部,中断类型码通过数据总线送入CPU(和内中断区别:不是CPU产生的)
    • 其他和内中断设置相同
    • 初始IF=0
    • 设置IF=1:sti
    • 设置IF=0:cli
  • 不可屏蔽中断
    • 执行完当前指令后立即响应
    • 对于8086CPU,不可屏蔽中断的中断类型码位2,所以中断过程不需要取中断类型码
  • 几乎所有外设引发的中断都是可屏蔽的

    键盘处理过程

  • 键盘输入->引发9号中断->执行int 9中断例程

  • 按下和松开按键时的扫描码都被送入60H端口中
  • 按下键产生的扫描码:通码,1个字节,第7位为0
  • 松开键产生的扫描码:断码,1个字节,第7位为1
  • 断码=通码+80H
  • 工作过程
    • 1)读出60h端口中的扫描码
    • 2)如果是字符键的扫描码,将该扫描码和它对应的字符码(ASCII/UNICODE)送入内存中的BIOS键盘缓冲区;
    • 3)相关芯片向CPU发出中断类型码为9的可屏蔽中断信息
    • 4)CPU检测到中断信息后,如果IF=1,响应中断,转去执行int 9中断例程,IF置0,执行完后再IF置0
    • 5)如果是控制键,将其转变为状态字节,写入内存中存储状态字节的单元,输入输出时会检查这里的值;
  • BIOS键盘缓冲区:BIOS用于存放int 9中断例程所接收的键盘输入的内存区。
    • 可以存储15个键盘输入
    • 一个键盘输入用一个字单元存放:高位字节存放扫描码,低位字节存放字符码
  • 0040:17单元存储键盘状态字节,按位标志相关控制键和切换键的状态

模拟修改int9例程(依次显示a~z)

  1. assume cs:code
  2. stack segment
  3. db 128 dup(0)
  4. stack ends
  5. data segemnt
  6. dw 0,0
  7. data ends
  8. code segment
  9. start: mov ax,stack
  10. mov ss,ax
  11. mov sp,128 ;!!
  12. mov ax,data
  13. mov ds,ax
  14. mov ax,0
  15. mov es,ax
  16. push es:[9*4]
  17. pop ds:[0]
  18. push es:[9*4+2]
  19. pop ds:[2] ;将原来int 9中断例程的入口地址保存在ds:0ds:2单元中
  20. mov word ptr es:[9*4],offset int9
  21. mov es:[9*4+2],cs ;在中断向量表中设置新的int9的入口地址
  22. mov ax,0b800h
  23. mov es,ax
  24. mov ah,'a'
  25. s: mov es:[160*12+40*2],ah
  26. inc ah
  27. cmp ah,'z'
  28. call delay ;(time.sleep())
  29. jna s
  30. mov ax,0
  31. mov es,ax
  32. push ds:[0]
  33. pop es:[9*4]
  34. push ds:[1]
  35. pop es:[9*4+2];原本的中断例程恢复
  36. mov ax,4c00h
  37. int 21h
  38. delay:push ax
  39. push dx
  40. mov dx,1000h;循环10000000
  41. mov ah,0
  42. s1:sub ax,1
  43. sbb dx,0
  44. cmp ax,0
  45. jne s1
  46. cmp dx,0
  47. jne s1
  48. pop dx
  49. pop ax
  50. ret
  51. int9:push ax
  52. push bx
  53. push es
  54. in al,60h;获得键盘扫描码
  55. pushf ;保留int9模拟程序中的各个标志位
  56. ;模拟flagIFTF位在执行int中断例程时置零
  57. pushf ;模拟原始int中断的标志寄存器进栈
  58. pop bx ;栈里的flag
  59. and bh,11111100b ;TF IF标志位置0
  60. push bx ;修改后的flag入栈
  61. popf ;覆盖flag
  62. call dword ptr ds:[0];上面执行完个性化后,调用原来的int 9中断例程
  63. cmp al,1;键盘扫描码为1,改变颜色
  64. jne int9ret
  65. mov ax,0b800h ;显存段地址
  66. mov es,ax
  67. inc byte ptr es:[160*12+40*2+1];属性增加1,改变颜色
  68. int9ret:
  69. pop es,
  70. pop bx
  71. pop ax
  72. iret ;中断返回
  73. code ends
  74. end start

安装新的int 9中断例程(按F1键改变屏幕显示颜色,DOS实模式下才能成功)

  1. ;1)改变颜色
  2. mov ax,0b800h
  3. mov es,ax
  4. mov bx,1
  5. mov cx,2000 ;整个显存的所有字节
  6. s:inc byte ptr es:[bx]
  7. add bx,2
  8. loop s
  9. ;2)保存原int 9的入口地址
  10. ;3)安装新int 9的入口地址

指令系统总结

  • 数据传送指令
    • mov\push\pop\pushf\popf
    • xchg:两个寄存器,寄存器和内存变量之间内容的交换指令,两个操作数的数据类型要相同,可以是一个字节,也可以是一个字,也可以是双字。
  • 算术运算指令(影响sf、zf、of、cf、pf、af位)
    • add\sub\adc\sbb\inc\dec\cmp\imul\idiv\aaa
    • imul:将被乘数与乘数均作为有符号数, 它按照符号扩展方式扩展到目标操作数格式的长度
  • 逻辑指令(除了not指令外,其他都会影响flag相关标志位)
    • and\or\not\xor\test\shl\shr\sal\sar\rol\ror\rcl\rcr
  • 转移指令(可以修改CS和IP或单一修改IP)
    • jmp\jcx\je\jb\ja\jnb\jna\loop\call\ret\retf\int\iret
  • 处理机控制指令
    • cld\std\sli\sti\nop\clc\cmc\stc\hlt\wait\esc\lock
  • 串处理指令
    • movsb\movsw\cmps\scas\lods\stos