第10章 中断和动态时钟显示

第10章 中断和动态时钟显示

从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。

书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。

我自己理解中断的一些作用:

  • 为了更好的利用处理器的性能。
  • 协同快速和慢速设备一起工作。
  • 重要程序和一般程序的优先级处理。

外部硬件中断

外部硬件中断是通过两个信号线引入处理器内部的,这两根线的名字就叫 NMI(Non Maskable Interrupt) 和 INTR((Interrupt Request)) 。

image

两条信号线的区别:

  • 从 INTR 输入的中断信号叫作可屏蔽中断,不紧急的中断信号走这条线。
  • 从 NMI 引脚来的中断信号称为非屏蔽中断,必须进行处理。

非屏蔽中断

每种类型的中断都被统一编号,这称为中断类型号、中断向量或者中断号。实模式下,NMI被赋予了统一的中断号2

可屏蔽中断

可屏蔽中断需要通过代理来接收外部设备发出的中断信号。

早使用的中断代理就是8259芯片,它就是通常所说的中断控制器。

INTEL处理器允许256个中断,中断号的范围是0~255,8259负责提供其中的15个,但中断号并不固定。它又叫可编程中断控制器(Programmable Interrupt Controller, PIC)。

image

8259有主片和从片(图片来源书籍)

8259芯片的一些知识,涉及后面编程用:

  • 主片的端口号是0x20和0x21;
  • 从片的端口号是0xa0和0xa1;

中断标志(Interrupt Flag):处理器内部,标志寄存器有一个标志位IF。

  • IF = 0,忽略INTR中断信号;
  • IF = 1,可以接受和响应中断。

image

IF标志位可以通过 cli 和 sti 改变。

  • cli(Clear Interrupt Flag):IF = 0
  • sti(Set Interrupt Flag):IF = 1

实模式下的中断向量表

中断向量表(Interrupt VectorTable, IVT):在实模式下,处理器要求将它们的入口点集中存放到内存中从物理地址0x00000开始到0x003ff结束,共1KB的空间内,这就是所谓的中断向量表。

中断向量表表项格式:每个中断在中断向量表中占2个字(4字节),分别是中断处理程序的偏移地址逻辑段地址

image

图片来源书籍

处理中断的步骤:

  1. 保护断点的现场。

    a. 将标志寄存器FLAGS压栈;
    b. 清除它的IF位和TF位;
    c. 将当前的代码段寄存器CS和指令指针寄存器IP压栈。

  2. 执行中断处理程序。

    a. 中断号乘以4(每个中断在中断向量表中占4字节);
    b. 就得到了该中断入口点在中断向量表中的偏移地址;
    c. 从表中依次取出中断程序的偏移地址和段地址,并分别传送到IP和CS。

  3. 返回到断点接着执行。

    a. 使用中断返回指令iret,处理器依次从栈中弹出(恢复)IP、CS和FLAGS的原始内容,转到中断处接着执行。

NMI中断号:NMI发生时,处理器不会从外部获得中断号,它自动生成中断号码2。

中断向量表建立:中断向量表的建立和初始化工作是由BIOS在计算机启动时负责完成的,我们可以更改为自己编写的中断程序。

实时时钟、CMOS RAM和BCD编码

实时时钟(Real Time Clock, RTC):负责计算时间。

CMOS RAM:静态存储器,存储RTC计算的时间。

书中有提供了表格说明了CMOS中的时间信息,只是没有提供范围,网上另外找到相关的范围信息,可供参考。

image

CMOS中的时间信息(来源:[osdev](https://wiki.osdev.org/CMOS))

CMOS RAM访问:需要通过两个端口进行。

  • 0x70或者0x74是索引端口,用来指定CMOS RAM内的单元
  • 0x71或者0x75是数据端口,用来读写相应单元里的内容。

例如读取今天是星期几:

mov al,0x06 ;设置从0x06读取数据,这里存储的是星期几的信息
out 0x70,al ;通过索引端口写入0x06
in al,0x71  ;通过数据端口读取数值保存到al 

BCD编码(Binary Coded Decimal):CMOS RAM中保存的日期和时间通常是以二进制编码的十进制数(BCD)。

简单说就是每4位二进制编码表示十进制的一个数位,参考下图:

image

和十六进制很像,就是每个数位最多表示到9就可以了。

实时时钟RTC的中断信号

实时时钟RTC电路可以产生三种中断信号:

  • 周期性中断(Periodic Interrupt, PF)
  • 更新周期结束中断(Update-ended Interrupt, UI)
  • 闹钟中断(Alarm Interrupt, AI)。

周期性中断:每隔一段时间重复发生一次。速度是可以调节的,最慢500ms,最快30.517μs。

更新周期结束中断:隔一秒,实时时钟电路将更新CMOS RAM里面的时间和日期,在每个更新周期结束时,如果允许的话,实时时钟电路可以发出一个中断信号,表示本次更新周期已经结束,这就叫更新周期结束中断。

闹钟中断:当实时时钟到达指定的闹点时,如果允许的话,将产生闹钟中断信号。

代码清单10-1

该章的代码示例是用来展示一个会走的时钟:
image

初始化8259、RTC和中断向量表

设置栈段期间禁止中断:一开始的代码和上章类似,初始化栈段和数据段,打印一些信息。只是这章提到了一点,就是设置栈段的时候,因为涉及到SS和SP两个寄存器的更改,在这之间是是禁止中断的。
image

修改中断向量表:在计算机启动期间,BIOS会初始化中断控制器,将主片的中断号设为从0x08开始,将从片的中断号设为从0x70开始。所以,计算机启动后,RTC芯片的中断号默认是0x70。

更改RCT状态:通过修改RCT寄存器B和C,允许更新周期照常发生,禁止周期性中断,禁止闹钟功能,允许更新周期结束中断,使用24小时制,日期和时间采用BCD编码。

修改8259芯片,允许RTC中断:修改中断屏蔽寄存器IMR的位0为0,表示允许RTC中断。

image

这一块的代码并不难理解,就是根据硬件的规定读写数据即可。

使处理器进入低功耗状态

.idle:
    hlt                        ;使CPU进入低功耗状态,直到用中断唤醒
    not byte [12*160 + 33*2+1] ;反转 @ 字符显示属性 
    jmp .idle

hlt指令:使CPU进入低功耗状态,直到用中断唤醒。

not指令:会将操作数的每一位反转,原来的0变成1,原来的1变成0。

not r/m8
not r/m16

例如:

mov al,0x1f   ; 0001_1111
not al        ; AL的内容为 1110_0000, 十六进制0xe0

这里主要是将 @ 字符的显示属性进行反转,作者在这里主要是想做一个动画效果。

image

自己写了例子,可以单独运行,有需要的可以自己运行看看效果。

mov ax,0xB800
mov es,ax

mov di,0 

mov byte [es:di],'1' ;默认是黑底白字。 
inc di
not byte [es:di]    ; 反转显示属性,白底黑字、闪缩、高亮

jmp $
times 510-($-$$) db 0
db 0x55,0xaa

实时时钟中断的处理过程

实时时钟中断的处理过程就是 new_int_0x70 这个过程了。

检测UIP位(Update In Progress):一开始要检测一下 UIP 位。

  • UIP为0,则表示现在访问CMOS RAM中的日期和时间是安全的。
  • UIP为1,则表示正处于更新周期,或者马上要启动。

image

这里用到了test指令:用于测试某个寄存器,或者内存单元里的内容是否带有某个特征。

test r/m8, imm8
test r/m16, imm16
test r/m8, r8
test r/m16, r16

例子:

test al,0x04 ;测试al的位3是否为1
             ;如(al)=xxxx_x0xx,则标志位ZF=1
             ;如(al)=xxxx_x1xx,则标志位ZF=0        

一开始被这个test和jnz命令弄的有点混乱,列个表格梳理一下就清楚了:

image

读取秒、分、时:按照偏移地址读取即可。读取后的数据进行压栈处理,后面再一起统一显示。我增加了一些代码注释,更容易理解。

xor al,al        ;al清0,偏移地址0x00表示秒:0~59
or al,0x80       ;阻断NMI。
out 0x70,al      ;写入索引端口
in al,0x71       ;读RTC当前时间(秒)
push ax          ;压栈

mov al,2         ;偏移地址0x02表示分钟:0~59
or al,0x80
out 0x70,al
in al,0x71       ;读RTC当前时间(分)
push ax          ;压栈       

mov al,4         ;偏移地址0x04表示时:0~23
or al,0x80
out 0x70,al
in al,0x71        ;读RTC当前时间(时)
push ax           ;压栈

复位RTC中断标志:根据寄存器C的特性,读一下这个寄存器就可以了,表示中断得到处理了,否则RTC将不再产生中断信号。

显示时间信息:思路也容易理解,就是依次从栈顶弹出时、分、秒然后进行显示。

代码我加了一些注释,方便理解。

pop ax                  ;弹出栈顶,栈顶存储的是:时       
call bcd_to_ascii
mov bx,12*160 + 36*2    ;从屏幕上的12行36列开始显示

mov [es:bx],ah
mov [es:bx+2],al        ;显示两位小时数字

mov al,':'
mov [es:bx+4],al         ;显示分隔符':'
not byte [es:bx+5]       ;反转显示属性 

pop ax                   ;弹出栈顶,栈顶存储的是:分         
call bcd_to_ascii
mov [es:bx+6],ah
mov [es:bx+8],al         ;显示两位分钟数字

mov al,':'
mov [es:bx+10],al        ;显示分隔符':'
not byte [es:bx+11]      ;反转显示属性

pop ax                   ;弹出栈顶,栈顶存储的是:秒
call bcd_to_ascii
mov [es:bx+12],ah
mov [es:bx+14],al        ;显示两位小时数字

这里封装了一个bcd_to_ascii过程,也容易理解,就是每4位转一个ascii码。具体思路就是:

  • 借助ah转高4位。
  • al转低4位。

中间还有一个反转冒号“:”的显示属性操作,主要是为了看这个中断处理过程的周期效果,每秒执行1次。

发送中断结束命令(End Of Interrupt, EOI):将8259芯片内中断服务寄存器(Interrupt Service Register, ISR)的每位清0,表示可以接受新的中断。
中断结束命令的代码是0x20。主片和从片都要发送,这容易理解。

从栈中恢复数据到寄存器:这个容易理解,基本每个过程都有。

iret返回:中断要用这个指令返回,表示Interrupt Return。

代码清单10-1的编译和运行

image

  • @符号一直在闪烁。
  • 中间显示时钟,每秒走一次。
  • 时钟之间的冒号1秒闪烁一次,频率和时钟一致的。

内部中断

内部中断是在处理器内部本身发生的,比如

  • 除以0,中断类型号为0 ;
  • 非法指令,中断类型好位6。

尝试写了一个触发除法异常的例子,加强理解一下。

思路:

  • 声明中断0的处理方法,就是在屏幕上打印一个0。
  • 重写中断向量表0号中断的处理方法。
  • 通过除以0触发0号中断观察运行效果。
jmp near start

new_int_0x00:               ;中断0的处理方法。
    push ax
    push bx
    push es

    mov ax,0xb800           ;在屏幕上打印一个0
    mov es,ax
    mov bx,0
    mov byte [es:bx],'0'

    pop es
    pop bx
    pop ax

    iret

start: 
    ;重新中断向量表0号中断
    mov ax,0x0000
    mov es,ax
    mov bx,0x00
    mov word [es:bx],new_int_0x00+0x7c00      ;偏移地址。
    mov word [es:bx+2],cs              ;段地址

    ;除以0触发处理器内部中断0
    mov ax,10           
    mov bx,0
    div bx

jmp $
times 510-($-$$) db 0
db 0x55,0xaa

软中断

软中断:在编写程序的时候,我们可以随时用指令来产生中断,这种类型的中断叫作软中断。

软中断的指令包括以下几种:

int3        ; 断点中断指令
int imm8    ; 
into 
  • int3是断点中断指令,机器指令码为0xCC。
  • int指令的机器码为2字节,第一字节是操作码0xCD,第2字节给出了中断号。
int 0x00            ;机器码为 CD 00 引发 0 号中断
int 0x15            ;机器码为 CD 15 引发 0x15 号中断
int 0x16            ;机器码为 CD 16 引发 0x16 号中断
  • into是溢出中断指令,机器码为0xCE,也是单字节指令。当处理器执行这条指令时,如果标志寄存器的OF位是1,那么,将产生4号中断。

BIOS中断

BIOS中断:又称BIOS功能调用,主要是为了方便地使用最基本的硬件访问功能。

以下指令用于从键盘读取一个按键:

mov ah,0x00    ;从键盘读取字符
int 0x16       ;键盘服务,返回时,字符代码在寄存器AL中

BIOS中断什么时候安装:在BIOS执行期间安装的,当主引导程序开始执行时,就可以在程序中使用了。

BIOS中断怎么安装

  • BIOS可能会为一些简单的外围设备提供初始化代码和功能调用代码,并填写中断向量表,
  • 有一些BIOS中断是由外部设备接口自己建立的。

BIOS中断手册:可以查看底部参考资料。

代码清单10-2

该代码用来演示BIOS中断,功能就是通过BIOS中断,可以屏幕上进行输入。
image

从键盘读字符并显示

向屏幕上写字符使用的是BIOS中断,具体说就是中断0x100x0e号功能,该功能用于在屏幕上的光标位置处写一个字符,并推进光标位置。

    mov cx,msg_end-message
    mov bx,message

.putc:               ;显示字符
    mov ah,0x0e      ;功能号0x0e:显示字符,光标前移。
    mov al,[bx]      ;参数:bx指向的字符
    int 0x10         ;0x10号中断:显示功能
    inc bx           ;显示下一个字符
    loop .putc  

从键盘读取字符再显示在屏幕上,代码我加了一些注释:

.reps:
    mov ah,0x00   ;0x00功能号:读取字符
    int 0x16      ;0x16号中断:键盘功能
                ; 返回:AL=字符码(ASCII码) AH=扫描码
    mov ah,0x0e   ;功能号0x0e:显示字符,光标前移。               
    mov bl,0x07   ; 参数:AL=字符、BL=前景色(图形模式)、BH=页码
    int 0x10      ;0x10号中断:显示功能
    
    jmp .reps

代码清单10-2的编译和运行

image

可以在屏幕上输入字符。

参考资料

  • CMOS:https://wiki.osdev.org/CMOS
  • RTC:https://wiki.osdev.org/RTC
  • Interrupts:https://wiki.osdev.org/Interrupts
  • 微机原理——8086中断类型以及中断向量表、中断响应、中断返回_8086 int-CSDN博客
  • BIOS中断表(整理更新中2013-10-23)_int13h 256色-CSDN博客

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

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

相关文章

jantic/DeOldify部署(图片上色)附带Dockerfile和镜像

克隆代码到DeOldify git clone https://github.com/jantic/DeOldify.git DeOldifyDeOldify源码 安装依赖 这里会安装python以及创建deoldify环境 cd DeOldify conda env create -f environment.yml(base) rootDESKTOP-1FOD6A8:~/DeOldify# conda env create -f environment.ym…

MySQL递归查询

一、为什么要使用MySQL递归查询 在很多场景下有树形表需要去遍历,若通过编程语言去递归遍历树将多次进行与数据库的交互操作,相当于100个葡萄去楼下超市买100次,在路上多走了99次浪费了大量时间,肯定不如一次买100葡萄省事。所以与…

景联文科技:专业数据标注公司,推动AI技术革新

数据标注作为AI技术发展的重要支撑,对于训练高质量的机器学习模型以及推动应用领域的创新具有不可替代的作用。 景联文科技作为专业的数据标注公司,致力于提供专业的数据标注服务,帮助客户解决AI链条中的数据处理难题,共同推动人工…

2024霸王餐小程序cps,h5公众号小程序开源版系统搭建开发,外卖霸王餐小程序系统源码

目录 前言: 一、霸王餐小程序的操作是怎么样的? 二、霸王餐系统后台 三、怎么搭建部署? 前言: 霸王餐项目基于美团和饿了么平台开发的小程序。 一、霸王餐小程序的操作是怎么样的? 1、进入小程序后选择自己要下单的店铺&am…

RTMP播放器延迟最低可以做到多少?

技术背景 RTMP播放器的延迟可以受到多种因素的影响,包括网络状况、推流设置、播放器配置以及CDN分发等。因此,RTMP播放器的延迟并不是一个固定的数值,而是可以在一定范围内变化的。 正常情况下,网上大多看到的,针对R…

华为手机找不到wifi调试?不急,没有wifi调试一样可以进行局域网模式调试

最近小黄在使用uniapp启动无线调试的时候突然发现华为的手机突然找不到wifi调试了,那么我们怎么进行无线调试呢? 其实他只是找不到开关而已,正常使用就行。 1.使用数据线连接手机。 打开cmd命令行执行:adb tcpip 5555 2.再执行ad…

论文120:Giga-SSL: Self-supervised learning for gigapixel images (2023, CVPR, 开源)

文章目录 1 要点2 方法2.1 算法设计2.2 设计选择 1 要点 题目:用于千兆像素图像的自监督学习 (Giga-SSL: Self-Supervised Learning for Gigapixel Images) 代码:https://github.com/trislaz/gigassl 研究目的: 现有的WSI分类方法依赖于有…

云计算之大数据(上)

目录 一、Elasticsearch 1.1 产品组件 1.1.1 X-Pack 1.1.2 Beats数据采集中心 1.1.3 Logstash 1.1.4 Kibana 1.2 架构特性 1.2.1 性能 1.2.2 安全性 1.2.3 可用性 1.2.4 可扩展性 1.2.5 可维护性 1.2.6 国际化 1.3 综合检索分析 1.4 全观测 1.5 大数据检索加速…

PAT甲级-1029 Median

题目 题目大意 给定两个递增序列,求这两个序列合并为一个递增序列后的中位数。 思路 直接用一个数组接收两个数组的输入,然后用sort()暴力求解,也可以过,但是时间复杂度较高。 更好的方法是双指针法,两个数组各一个…

在线plotly绘制动态旭日图,展示复杂数据层次结构

探索数据的层次之美:旭日图,以环环相扣的视觉效果,清晰展现数据的层级关系。搭配Plotly的动态可视化技术,不仅让数据层次一目了然,更通过交互式操作,让用户轻松探索每个层级的详细信息,享受数据…

解决移动端1px 边框优化的8个方法

前言 您是否注意到 1px 边框在移动设备上有时会显得比预期的要粗?这种不一致源于移动屏幕的像素密度不同。 在 Web 开发中,我们使用 CSS 来设置页面样式。但是,CSS 中的 1px 并不总是转换为设备上的物理 1px。这种差异就是我们的“1px 边框…

如何在网上找客户资源

在网上寻找客户资源可以通过多种渠道和方法来实现,这些方法结合不同的工具和平台,可以帮助你快速定位目标客户。以下是一些常见且有效的途径: 1. 利用搜索引擎 使用搜索引擎(如百度、Google)通过关键词搜索目标客户或…

JAVA一键开启缘分之旅红娘相亲交友系统小程序源码

一键开启缘分之旅 —— 红娘相亲交友系统 💖 初遇心动,一键启程 在这个快节奏的时代,找到那个对的人似乎成了一种奢侈。但别担心,有了“红娘相亲交友系统”,你的缘分之旅只需一键即可开启!无需复杂的注册流…

张雪峰:物联网行业迎高光时刻!如何选择?我们诚聘销售工程师!

作为一间10多年的物联网公司,各位求职人士可以看看我们其中一个招聘要求,和自己需求结合分析分析,希望对你们有所帮助。 【公司实力底蕴】 盈电智控物联网科技(广东)有限公司,2024年7月成立,是…

git pull之后发现项目错误,如何回到之前的版本方法

目录 首先我们打开小程序的cmd的黑窗口,git reflog查看之前的版本 之后再git reset --hard main{1} 我这个就已经返回了之前的6daaa2e的版本了 首先我们打开小程序的cmd的黑窗口,git reflog查看之前的版本 之后再git reset --hard main{1} 我这个就已…

深度学习的发展历程

深度学习的起源 在机器学习中,我们经常使用两种方式来表示特征:局部表示(Local Representation)和分布式表示(Distributed Representation)。以颜色表示为例,见下图: 要学习到一种好…

自动驾驶ADAS算法--使用MATLBA和UE4生成测试视频

原文参考:金书世界 环境搭建参考:用MATLAB2020b和虚拟引擎(Unreal Engine)联合仿真输出AVM全景测试视频----Matlab环境搭建 matlab参考: https://ww2.mathworks.cn/help/driving/ug/simulate-a-simple-driving-sce…

分库分表核心理念

文章目录 分库,分表,分库分表什么时候分库?什么时候分表?什么时候既分库又分表?横向拆分 & 纵向拆分 分表算法Range 范围Hash 取模一致性 Hash斐波那契散列 严格雪崩标准(SAC)订单分库分表实…

导入word模板的数据到DB,偏自学,可自改套用

GetMapping("/importTestPeople")public void importTestPeople(RequestParam("file") MultipartFile multipartFile) throws IOException {InputStream inputStream null;File file null;try {// 创建临时文件file File.createTempFile("temp&quo…

从0开始深入理解并发、线程与等待通知机制

1、 从0开始深入理解并发、线程与等待通知机制 从上面两大互联网公司的招聘需求可以看到,大厂的Java岗的并发编程能力属于标配。 而在非大厂的公司,并发编程能力也是面试的极大加分项,而工作时善用并发编程则可以极大提升程序员在公司的技术…