《汇编语言》- 读书笔记 - 第15章-外中断

《汇编语言》- 读书笔记 - 第15章-外中断

  • 15.1 接口芯片和端口
  • 15.2 外中断信息
    • 1. 可屏蔽中断(Maskable Interrupt)
    • 2. 不可屏蔽中断(Non-Maskable Interrupt)
    • 设计思想
  • 15.3 PC 机键盘的处理过程
    • 1. 键盘输入
    • 2. 引发 9 号中断
    • 3. 执行 int 9 中断例程
  • 15.4 编写int9 中断例程
    • 编程
    • 思路
    • 代码
    • 检测点 15.1
  • 15.5 安装新的 int 9 中断例程
    • 分析
    • 代码
    • 运行效果
  • 实验 15 安装新的 int9 中断例程

CPU通过中断机制得知外部输入事件,并通过I/O接口数据总线实现与外设的数据交换,从而实现对外设输入的有效处理。

CPU 对外设输入的通常处理方法:

  1. 外设的输入送入端口;
  2. 向 CPU 发出外中断(可屏蔽中断)信息;
  3. CPU 检测到可屏蔽中断信息;
    3.1. 如果 IF=1,CPU 在执行完当前指令后响应中断,执行相应的中断例程;
  4. 可在中断例程中实现对外设输入的处理。

端口和中断机制,是 CPU 进行 I/O 的基础。

15.1 接口芯片和端口

CPU 通过端口外部设备进行联系。

15.2 外中断信息

外部设备 在完成一系列自己的工作后,需要将产生的数据状态发给CPU处理时,就会触发外中断

  • 中断信息的发送过程大致如下:
  1. 中断请求信号
    外设芯片在适当时候会通过自身的中断输出引脚向主板上的中断控制器发送中断请求信号,这通常表现为一个电信号的变化。例如在8086体系结构中,外设可以通过INTR(Interrupt Request)线向CPU发出中断请求。

  2. 中断控制器
    主板上的中断控制器(如Intel 8259A可编程中断控制器)负责接收来自多个外设的中断请求,并根据它们的优先级和中断向量进行管理。中断控制器会将有效的中断请求打包并通过IRQ(Interrupt Request Line)线传输到CPU。

  3. CPU响应中断
    当CPU在执行完当前指令后检查中断请求线时,如果发现有中断请求存在,它会暂停当前任务,保存现场,然后通过读取中断向量表(IVT)获取中断服务程序(ISR)的地址,跳转到相应的处理程序执行中断处理。

  4. 线路连接
    中断请求信号的传送是通过主板上的硬件连线完成的。例如在8086/8088系统中,外设与CPU间的中断请求线和中断响应线(INTA#)是主板上的物理连接线,它们属于系统总线的一部分,通过这些线路上的电信号变化来进行中断请求和响应的通讯。

注意,随着技术的发展,更现代的计算机系统可能采用了更为复杂和高级的中断控制器和总线标准,但核心原理仍然是外设通过特定线路发送中断信号给CPU,并由CPU依据一定的优先级策略来响应和处理中断。

1. 可屏蔽中断(Maskable Interrupt)

可屏蔽中断 | CPU在收到可屏蔽中断时会根据 CF 的状态来决定:执行完当前指令是否响应

IF 状态响应不响应
IF = 1
IF = 0
  • 中断过程
    可屏蔽中断中断过程除了中断类型码是通过数据总线外部传进CPU的,其它与内中断相同。

我们可以通过指令(STI, CLI)设置IF来控制是否响应可屏蔽中断

———— 指 令 ———— 功 能 描述
cli
(Clear Interrupt Flag)
IF=0
禁止中断
CPU执行cliIF=0后,仅保留对不可屏蔽中断(NMI)的响应,直至遇到STI指令为止。
此操作有助于保护在执行重要且不能被打断的代码时,不被中断处理程序打乱。
例如: 在更改栈指针(SS:SP)时,需要防止因中断处理程序介入而破坏栈的状态。
sti
(Set Interrupt Flag)
IF=1
允许中断
CPU执行stiIF=1后,重新开启中断响应功能。CPU会再次响应挂起的中断请求,恢复正常的中断处理流程。这对于完成关键区域操作后恢复系统的正常中断响应至关重要。
  • 在IF=0期间,中断请求不会丢失,但会被延迟处理,等待CPU重新打开中断响应后,按照中断控制器维护的队列顺序逐一处理。是否超时以及超时后的处理方法取决于设备本身的特性以及操作系统的调度策略。
    硬件中断控制器(如Intel 8259A可编程中断控制器)负责管理和维持中断请求的排队。
  • CLISTI结合运用,构建短暂的中断防护区域,确保其间代码免受外部中断影响,待关键操作完成后通过STI恢复中断响应,保障系统并发处理能力和实时响应性能。在多任务OS中,内核常在切换进程环境、管控硬件资源等关键场景调用这两条指令。

2. 不可屏蔽中断(Non-Maskable Interrupt)

当不可屏蔽中断发生时,CPU会立即停止当前的执行流程,保存必要的上下文信息,然后跳转到预设的NMI处理程序去执行相应的处理代码。
即使在 CPU 执行 CLI 指令 禁止了可屏蔽中断 的情况下也不例外。
由于NMI的重要性,其处理过程一般要求快速、简洁,尽量减少对系统运行的影响。

  • NMI触发的原因可能包括但不限于以下几种情况:
    1. 硬件故障:如电源故障、内存错误、严重硬件故障等;
    2. 系统调试需求:在调试环境中,开发者可能通过人工或硬件手段触发NMI,以便快速进入调试模式;
    3. 监控程序:某些嵌入式系统或服务器中,监控程序可能会通过NMI报告严重的系统错误或警告;
    4. 性能计数器溢出:某些高性能处理器中,性能监控单元(PMU)的计数器溢出可能导致NMI。

设计思想

可屏蔽中断:几乎都是外设触发的。告诉CPU来活了。
不可屏蔽中断:是发生了必须紧急处理的事件。CPU要先解决它了再说别的。

15.3 PC 机键盘的处理过程

1. 键盘输入

键盘上每个键分:按下松开两种状态都会产生相应的扫描码
按下时的叫通码,松开时的叫断码
它会被送入主板上的相关接口芯片的寄存器中,该寄存器的端口地址为 60h

断码 = 通码 + 80h
比如: g 键的通码为 22h,断码为 a2h。
表 15.1 是键盘上部分键的扫描码,只列出通码。
在这里插入图片描述

2. 引发 9 号中断

60h 端口收到信号,相关的芯片就会向 CPU 发出中断类型码9可屏蔽中断信息。
CPU 收到后,如果 IF=1,则响应中断,引发中断过程,转去执行 int 9 中断例程。

3. 执行 int 9 中断例程

BIOS 提供 int 9 中断例程,处理基本的键盘输入:

  1. 首先,中断例程通常会从60h端口读取扫描码。
  2. 处理扫描码
    2.1. 若是字符键,则将扫描码转换为ASCII码,存入键盘缓冲区。 2.2. 若是功能键控制键,则可能更新内存中的键盘状态字节`或其他内部状态。
  3. 向键盘控制器发送应答信号,表明中断已被处理。

BIOS键盘缓冲区:

  1. BIOS键盘缓冲区是系统启动时BIOS设置的一块内存区域,用于存储15个键盘输入事件,每个事件占用2字节,其中高位字节为扫描码低位字节为字符码
  2. 这个缓冲区通过int 9中断机制收集并暂存键盘输入,确保在操作系统尚未完全加载或正忙时也能记录用户的按键动作。
字单元(1)字单元(2)字单元(15)
高位-扫描码高位-扫描码高位-扫描码
低位-字符码低位-字符码低位-字符码

0040:17 单元存储键盘状态字节,该字节记录了控制键和切换键的状态。字节各位信息如下。

状态
0右 Shift 状态,置1表示按下右 Shift 键:
1左 Shitt 状态,置1表示按下左 Shit 键;
2Ctrl 状态,置1表示按下 Ctrl 键;
3Alt 状态,置1表示按下 Alt 键;
4ScrollLock状态,置1表示 Scroll 指示灯亮;
5NumLock 状态,置1表示小键盘输入的是数字;
6CapsLock 状态,置1表示输入大写字母:
7Insert 状态,置1表示处于删除态。

15.4 编写int9 中断例程

键盘输入的处理过程:

  1. 键盘产生扫描码;
  2. 扫描码送入 60h 端口;
  3. 引发 9 号中断;
  4. CPU 执行 int 9 中断例程处理键盘输入。

前三步都是硬件系统的活,我们能插手的就只有第4步。但因为 int 9 中断处理程序要与一些硬件细节打交到。所以我们只对 int 9 做下封装扩展。

编程

在屏幕中间依次显示“a”~“z”,并可以让人看清。在显示的过程中,按下 Esc 键后,改变显示的颜色。

思路

  1. 先循环显示 a ~ z。(为了看清,书上给的方案是空循环模拟延迟效果)
  2. 自己写一个 int 9 代替原版。
    2.1. 我们自己的int 9中调用原版 int 9
    2.2. 拿到原版 int 9 返回的扫描码。
    2.3. 判断如果是 Esc 修改显存改变颜色

代码

assume cs:code
stack segment
	db 128 dup(0)
stack ends

data segment
	oint9 dw 0,0
data ends

code segment
 start: mov ax,stack		; 设置栈段和栈顶位置
		mov ss,ax
		mov sp,128
		
		mov ax,data			; 设置数据段
		mov ds,ax
		
		mov ax,0			; 设置附加段
		mov es,ax

		; ------------ 保存原 int 9 中断列和入口到 ds:0, ds:2 ------------
		push es:[9*4]
		pop ds:[0]
		push es:[9*4+2]
		pop ds: [2]
		
		; ---------------- 将我们的新 int 9 写入中断向量表 ----------------
		mov word ptr es:[9*4],offset int9
		mov es:[9*4+2],cs

		; ------------------------- 显示 a 到 z  -------------------------
		mov ax,0b800h	; 设置显存段
		mov es,ax
		mov ah,'a'		; 要显示的字符串,从 a 开始
	s:	mov es:[160*12+40*2],ah		; 显示字符
		call delay		; 调用子程序:延时
		inc ah			; 下一个字符
		cmp ah,'z'		; 如果不是z继续循环
		jna s

		; ------------- 将中断向量表中 int 9恢复为原来的地址 -------------
		mov ax,0
		mov es,ax
		push ds:[0]
		pop es:[9*4]
		push ds:[2]
		pop es:[9*4+2]
		
		mov ax,4c00h
		int 21h
; =======================================================	
; --------------------- 子程序 delay  -------------------
; 让CPU空循环,模拟延时效果
; -------------------------------------------------------
; 参数:; 返回:; -------------------------------------------------------
delay:
		push ax 		; 备份寄存器
		push dx
		
		mov dx,2h		; 循环 2h 次,可以自己把握
		mov ax,0
delays:	sub ax,1
		sbb dx,0		; 10000000h 循环递减
		cmp ax,0		; 直到 ax, dx 都为 0 才跳出循环
		jne delays
		cmp dx,0
		jne delays
		
		pop dx			; 还原寄存器
		pop ax
		ret				; 返回
; ---------------------- 子程序 delay -------------------
; =======================================================

; =======================================================	
; --------------------- 子程序 int 9  -------------------
; 调用原 int 9 获取扫描码,实现按 Esc 变色
; -------------------------------------------------------
; 参数:; 返回:; -------------------------------------------------------
int9:
		push ax 		; 备份寄存器
		push dx
		push es
		
		in al,60h		;60h端口读取数据
		
		pushf
		pushf
		pop bx
		and bh,11111100b
		push bx
		popf
		call dword ptr ds:[0] ; 调用原来的 int 9 中断例程
		
		cmp al,1
		jne int9ret
		
		mov ax,0b800h
		mov es,ax
		inc byte ptr es:[160*12+40*2+1]
		
int9ret:pop es			; 还原寄存器
		pop dx
		pop ax
		iret			; 返回
; --------------------- 子程序 int 9 ------------------
; =======================================================
code ends
end start

检测点 15.1

《汇编语言》- 读书笔记 - 各章检测点归档 - 检测点 15.1

15.5 安装新的 int 9 中断例程

任务安装一个新的 int9 中断例程。
功能在 DOS下,按F1键后改变当前屏幕的显示颜色,其他的键照常处理

分析

  1. 改变屏幕的显示颜色。
    改变从 B8000H 开始的 4000 个字节中的所有地址单元中的内容
	mov ax,0b800h
	mov es ax
	mov bx,1
	mov cx,2000
s: 	inc byte ptr es:[bx]
	add bx,2
	loop s
  1. 按键常规处理
    直接调用原 int 9

  2. 原 int9 入口地址
    不能保存在安装程序中。我们把它放在0:0200

  3. 安装新 int9 中断例程
    0:0200 ~ 0:0203用来保存原 int9 的地址了。
    我们保存新 int9 时从 0:0204 开始。

代码

assume cs:code
stack segment
	db 128 dup(0)
stack ends

code segment
 start: mov ax,stack		; 设置栈段和栈顶位置
		mov ss,ax
		mov sp,128
		
		; -------- 安装: 复制中断例程到目标内存 -------
		mov ax,cs			;设置 ds:si 指向源地址
		mov ds,ax
		mov si,offset int9
		mov ax,0			;设置 es:di 指向目的地址
		mov es,ax
		mov di,204h			
		mov cx,offset int9end-offset int9	;设置 cx为传输长度
		cld					;设置传输方向为正。movsb中si,di递增
		rep movsb			;重复复制数据次数由 cx 控制
		; -------- 安装: 复制中断例程到目标内存 -------
		
		; ---------- 备份原 int9 入口到 [0:200~0203] ----------
		push es:[9*4]
		pop es:[200h]
		push es:[9*4+2]
		pop es:[202h]
		; ---------- 备份原 int9 入口到 [0:200~0203] ----------
		
		; ---------- 设置中断向量表 ----------
		cli							; 临时屏蔽中断
		mov word ptr es:[9*4],204h	; 设置的偏移地址(0~3用来存原int9地址了)
		mov word ptr es:[9*4+2],0	; 设置的段地址
		sti							; 恢复中断
		; ---------- 设置中断向量表 ----------

	ok:	mov ax,4c00h
		int 21h

; =======================================================	
; --------------------- 子程序 int 9  -------------------
; 调用原 int 9 获取扫描码,实现按 Esc 变色
; -------------------------------------------------------
; 参数:; 返回:; -------------------------------------------------------
int9:
		push ax 		; 备份寄存器
		push bx
		push cx
		push es
		
		in al,60h		;60h端口读取数据
		
		; 模拟 int 指令,用 call 调用原 int 9
		pushf						; 进入中断后 IF、TF已经是0 直接入栈即可
		call dword ptr cs:[200h] 	; 调用原来的 int 9 中断例程
		
		cmp al,3bh		; 判断是否 F1 键
		jne int9ret		; 如果不是直接结束
		
		
		mov ax,0b800h	; 设置显存
		mov es,ax
		mov bx,1
		mov cx,2000
	s:	inc byte ptr es:[bx]
		add bx,2
		loop s
		
int9ret:pop es			; 还原寄存器
		pop cx
		pop bx
		pop ax
		iret			; 返回
int9end:nop

; --------------------- 子程序 int 9 ------------------
; =======================================================
code ends
end start

运行效果

在这里插入图片描述

实验 15 安装新的 int9 中断例程

《汇编语言》- 读书笔记 - 第15章-外中断-实验15 安装新的 int9 中断例程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/423641.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在您的下一个项目中选择 Golang 和 Node.js 之间的抉择

作为一名软件开发者,我总是在寻找构建应用程序的最快、最高效的工具。在速度和处理复杂任务方面,我认为 Golang 和 Node.js 是顶尖技术。两者在性能方面都享有极高的声誉。但哪一个更快——Golang 还是 Node?我决定深入一些硬核基准测试&…

Java+SpringBoot+Vue:志愿服务的数字化之旅

✍✍计算机毕业编程指导师 ⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流! ⚡⚡ Java、…

LeetCode 刷题 [C++] 第226题.翻转二叉树

题目描述 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 题目分析 深度优先搜索(DFS)- 递归方式 对于二叉树的镜像问题,很容易想到的就是使用递归来解决,自底向上依次翻转每一个节点…

DataX及Datax-web杂记

👽个人博客:https://everspring.github.io/ 👽公众号:爱历史的IT男 一. DataX调试 DataX之前调试不是很方便,要打包后才能调试。23年7月后一位叫"FuYouJ "的开源者提交了datax-example模块,就方…

蓝桥杯备战刷题two(自用)

1.杨辉三角形 #include<iostream> using namespace std; #define ll long long const int N2e510; int a[N]; //1 0 0 0 0 0 0 //1 1 0 0 0 0 0 //1 2 1 0 0 0 0 //1 3 3 1 0 0 0 //1 4 6 4 1 0 0 //1 5 10 10 5 1 //前缀和思想 //第一列全为1,第二列为从0开始递增1的序…

win安装卸载python3.13

一、安装 访问python官网&#xff1a;https://www.python.org/ 点击“Downloads” 点击“Windows” 找到自己要下载的版本和位数&#xff0c;比如我这个是3.13版本、64位的安装包 下载好了之后&#xff0c;双击安装包 勾选“Add python.exe to PATH”&#xff1a;把python环…

免费插件集-illustrator插件-Ai插件-雷达图-图表自动绘制

文章目录 1.介绍2.安装3.通过窗口>扩展>知了插件4.功能解释5.示例6.总结 1.介绍 本文介绍一款免费插件&#xff0c;加强illustrator使用人员工作效率&#xff0c;进行绘制雷达图。首先从下载网址下载这款插件 https://download.csdn.net/download/m0_67316550/87890501&…

Revit-二开之创建线性尺寸标注-(5)

创建线性尺寸标注 对应的Revit界面的按钮 线性尺寸标注源码 本篇文章实现的逻辑是从rvt文章中拾取一面墙,然后对墙添加再水平方向上的线性尺寸标注 protected override Result OnExecute(ExternalCommandData commandData, ref string message, ElementSet elements

MySQL基础-----SQL语句之DDL语句

目录 前言 开启登录数据库 一、数据库操作 1.查询所有数据库 2.切换使用数据库 3.查询当前使用的数据库 4.创建数据库 创建一个hello数据库, 使用数据库默认的字符集。 创建一个itheima数据库&#xff0c;并且指定字符集 5.删除数据库 二、表操作 1.查询当前数据库所有…

UE5中实现后处理深度描边

后处理深度描边可以通过取得边缘深度变化大的区域进行描边&#xff0c;一方面可以用来做角色的等距内描边&#xff0c;避免了菲尼尔边缘光不整齐的问题&#xff0c;另一方面可以结合场景扫描等特效使用&#xff0c;达到更丰富的效果&#xff1a; 后来解决了开启TAA十字线和锯齿…

基于ssm江苏融汇房地产营销策划有限公司的宣传网站

目 录 目 录 I 摘 要 III ABSTRACT IV 1 绪论 1 1.1 课题背景 1 1.2 研究现状 1 1.3 研究内容 2 2 系统开发环境 3 2.1 vue技术 3 2.2 JAVA技术 3 2.3 MYSQL数据库 3 2.4 B/S结构 4 2.5 SSM框架技术 4 3 系统分析 5 3.1 可行性分析 5 3.1.1 技术可行性 5 3.1.2 操作可行性 5 3…

c# 获取源码路径与当前程序所在路径

获取源码路径 private static string GetFilePath([CallerFilePath] string path null) {return path;}//当程序所在路径string str67 System.Environment.CurrentDirectory;//源码路径 var path GetFilePath();var directory Path.GetDirectoryName(path);参考

彻底搞懂回溯算法(例题详解)

目录 什么是回溯算法&#xff1a; 子集问题&#xff1a; 子集问题II(元素可重复但不可复选): 组合问题&#xff1a; 组合问题II(元素可重复但不可复选): 排列问题&#xff1a; 排列问题II(元素可重复但不可复选): 什么是回溯算法&#xff1a; 「回溯是递归的副产品&…

嵌入式学习31-指针和函数知识回顾

1.指针&#xff1a; 1.提供一种间接访问数据的方法 2.空间没有名字,只有一个地址编号 2.指针: 1.地址:区分不同内存空间的编号 2.指针:指针就是地址,地址就是指针 3.指针变量:存放指针的变量称为指针变量,简称为指针 3.指针的定义: int *p NULL; …

Github 2024-02-26 开源项目日报Top10

根据Github Trendings的统计&#xff0c;今日(2024-02-26统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目4C项目1Go项目1TypeScript项目1HTML项目1Jupyter Notebook项目1Rust项目1Shell项目1JavaScript项目…

keil MDK安装armcc V5编译器

不知道从什么时候开始&#xff0c;Keil MDK默认不支持V5的编译器了&#xff0c;里面默认只有V6的编译器&#xff0c;设置界面跟V5有很大的差异不太熟悉。最可怕的是&#xff0c;之前使用V5编译的工程&#xff0c;换成V6编译器后居然报错...虽然修改一下应该也可以正常编译&…

IOS 发布遇到“Unable to authenticate with App Store Connect”错误咋解决?

问题&#xff1a; 在开发ios app后&#xff0c;先发布adhoc版本&#xff0c;测试通过后&#xff0c;再发布testflight版本测试&#xff0c;但是可能会遇到一下问题。 解决办法&#xff1a; 在Signing &Capabilities中&#xff0c;在ios下边要指定有发布权限的Team账号&a…

30-k8s集群的七层代理-ingress资源(进阶知识)

一、ingress概述 1&#xff0c;引发问题 目前使用svc资源做网络暴露&#xff0c;使用nodeport类型&#xff0c;一个业务对应一个宿主机端口&#xff0c;那么如果业务多了&#xff0c;所占用的宿主机端口也就多了&#xff0c;虽然说宿主机端口一般情况下都是够用的&#xff0c;…

《YOLOv9:从入门到实战》报错解决 专栏答疑

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。《YOLOv9&#xff1a;从入门到实战》专栏上线后&#xff0c;部分同学在学习过程中提出了一些问题&#xff0c;笔者相信这些问题其他同学也有可能遇到。为了让大家可以更好地学习本专栏内容&#xff0c;笔者特意推出了该篇专…

1、Linux-安装

一、Linux和Windows的一些区别 1、Linux严格区分大小写——【Windows创建文件夹时不区分大小写】 2、Linux中所有内容都以文件形式存储&#xff0c;包括硬件 3、Linux不靠拓展名区分文件类型&#xff0c;而是可以通过读取文件开头的一些字节来区分。 但是在实际使用中一般要…