PART 1 >> 使用BIOS中断实现键盘输入的读取和显示

; File: c09_2.asm
; Date: 20191222; ===============================================================================
SECTION head vstart=0                       ; 定义用户程序头部段 ; 用户程序可能很大,16位可能不够program_length  dd program_end          ; 程序总长度[0x00]; 程序入口点(Entry Point)program_entry   dw beginning            ; 偏移地址[0x04]; 只是编译阶段确定的汇编地址。程序加载到内存后,需要根据加载的实际位置重新计算; 尽管在16位的环境中,一个段最长为64KB,但它却可以起始于任何20位的物理地址处。; 不可能用16位来保存20位的地址,所以需要32位dd section.code.start ; 汇编地址[0x06] realloc_tbl_size dw (head_end-segment_code_1)/4     ; 段重定位表项个数[0x0a]segment_code_1  dd section.code.start   ; [0x0c]    segment_data_1  dd section.data.start   ; [0x10]segment_stack   dd section.stack.start  ; [0x14]    ; 这里section 和 start 不能用大写 ???head_end:; ===============================================================================
SECTION code align=16 vstart=0beginning:; 设置用户程序自己的堆栈段; ds和es依然指向着用户程序头部head段mov ax, [segment_stack]mov ss, axmov sp, stack_end; 设置用户程序自己的数据段; 如果先初始化数据段ds和附加段es,那么头部head段中的数据将无法访问mov ax, [segment_data_1]mov ds, axmov cx, msg_end-messagemov bx, message.show_char:; 在频幕上写字符; 中断0x10的0x0e号功能。在屏幕光标位置处写一个字符,并推进光标位置。; Input: al, 字符mov ah, 0x0e        ; ah中指定0x0e号功能mov al, [bx]int 0x10inc bxloop .show_char.rw_keyboard:; 从键盘读字符; 中断0x10的0x00号功能。; Output: al, 字符mov ah, 0x00        ; ah中指定0x00号功能int 0x16mov ah, 0x0emov bl, 0x07int 0x10jmp .rw_keyboard; ===============================================================================
SECTION data align=16 vstart=0    message       db 'Hello, friend!',0x0d,0x0adb 'This simple procedure used to demonstrate 'db 'the BIOS interrupt.',0x0d,0x0adb 'Please press the keys on the keyboard ->'msg_end:; ===============================================================================
SECTION stack align=16 vstart=0   resb 256
stack_end:; ===============================================================================
SECTION program_tail
program_end:

===================================================================================================

PART 2 >> 使用RTC芯片实现实时时间的显示

; FILE: c09_1.asm
; DATE: 20191211; ===============================================================================
SECTION head vstart=0                       ; 定义用户程序头部段 ; 用户程序可能很大,16位可能不够program_length  dd program_end          ; 程序总长度[0x00]; 程序入口点(Entry Point)program_entry   dw beginning            ; 偏移地址[0x04]; 只是编译阶段确定的汇编地址。程序加载到内存后,需要根据加载的实际位置重新计算; 尽管在16位的环境中,一个段最长为64KB,但它却可以起始于任何20位的物理地址处。; 不可能用16位来保存20位的地址,所以需要32位dd section.code.start ; 汇编地址[0x06] realloc_tbl_size dw (head_end-segment_code_1)/4     ; 段重定位表项个数[0x0a]segment_code_1  dd section.code.start   ; [0x0c]    segment_data_1  dd section.data.start   ; [0x10]segment_stack   dd section.stack.start  ; [0x14]    ; 这里section 和 start 不能用大写 ???head_end:; ===============================================================================
SECTION code align=16 vstart=0beginning:; 设置用户程序自己的堆栈段; ds和es依然指向着用户程序头部head段mov ax, [segment_stack]mov ss, axmov sp, stack_end; 设置用户程序自己的数据段; 如果先初始化数据段ds和附加段es,那么头部head段中的数据将无法访问mov ax, [segment_data_1]mov ds, axmov bx, msg_init            ; 显示初识信息call show_stringmov bx, msg_install         ; 显示安装信息call show_string; 计算RTC芯片中断处理过程的段地址和偏移地址; RTC芯片的中断信号,通向中断控制器8259从片的第1个中断引脚IR0。; 计算机启动期间,BIOS会初始化中断控制器8259,将主片的中断号设为从0x08开始,从片的中断号从0x70开始。; 所以,计算机启动后,RTC芯片的中断号默认是0x70(可通过对8259编程来修改默认中断号)xor ax, axmov al, 0x70                ; RTC芯片的默认中断号0x70mov bl, 4                   ; 每个中断向量表项占4字节(段地址:偏移地址), 乘4,得中断像量表内的偏移mul blmov bx, axcli                         ; cli 清楚IF标志位,禁止中断,防止改动期间发生新的0x70号中断; 设置中断向量表0x70号表项内容; 实模式下,256个中断程序的入口点集中存放在内存0x00000~0x003FF共1KB的空间内,即中断向量表push esxor ax, axmov es, ax                  ; 将es指向中断向量表所在的段    mov word [es:bx], my_int_0x70    ; 中断处理过程的偏移地址    mov word [es:bx+2], cs           ; 段地址pop es; 不懂 ……; 设置RTC的工作状态,使它能够产生中断信号给8259中断控制器mov al,0x0b                        ;RTC寄存器Bor al,0x80                         ;阻断NMI out 0x70,almov al,0x12                        ;设置寄存器B,禁止周期性中断,开放更 out 0x71,al                        ;新结束后中断,BCD码,24小时制 mov al,0x0cout 0x70,alin al,0x71                         ;读RTC寄存器C,复位未决的中断状态in al,0xa1                         ;读8259从片的IMR寄存器 and al,0xfe                        ;清除bit 0(此位连接RTC)out 0xa1,al                        ;写回此寄存器 sti                         ; sti 放开中断,与cli相对应mov bx, msg_donecall show_string            ; 显示中断安装完成信息mov bx, msg_tipscall show_string            ; 显示提示信息; 屏幕中心显示字符@mov ax, 0xb800mov ds, axmov byte [12*160 + 33*2], '@'       ; 25row*80col    ; hlt 使处理器处于停机状态,停止执行指令,; 可以被外部中断唤醒并恢复执行.idle:hltnot byte [12*160 + 33*2 + 1] ; 反转上面@字符的显示属性jmp .idle; Function: 频幕上显示文本
; Input: ds:bx 字符串起始地址,以0结尾
show_string:mov cl, [bx]or cl, cljz .exitcall show_charinc bxjmp show_string.exit:ret; Function:
; Input: cl 字符
show_char:push axpush bxpush cxpush dxpush dspush es; 读取当前光标位置; 索引寄存器端口0x3d4,其索引值14(0x0e)和15(0x0f)分别用于提供光标位置的高和低8位; 数据端口0x3d5mov dx, 0x3d4   mov al, 0x0e   out dx, almov dx, 0x3d5in al, dxmov ah, almov dx, 0x3d4mov al, 0x0fout dx, almov dx, 0x3d5in al, dxmov bx, ax      ; 此处用bx存放光标位置的16位数; 判断是否为回车符0x0dcmp cl, 0x0d    ; 0x0d 为回车符jnz .show_0a    ; 不是回车符0x0d,再判断是否换行符0x0amov ax, bx      ; 是回车符,则将光标置位到行首mov bl, 80div blmul blmov bx, axjmp .set_cursor; ; 将光标位置移到行首,可以直接减去当前行吗??; mov ax, bx; mov dl, 80; div dl; sub bx, ah; jmp .set_cursor; 判断是否为换行符0x0a.show_0a:cmp cl, 0x0a    ; 0x0a 为换行符    jnz .show_normal; 不是换行符,则正常显示字符add bx, 80      ; 是换行符,再判断是否需要滚屏jmp .roll_screen; 正常显示字符; 在写入其它内容之前,显存里全是黑底白字的空白字符0x0720,所以可以不重写黑底白字的属性.show_normal:mov ax, 0xb800  ; 显存映射在 0xb8000~0xbffffmov es, axshl bx, 1       ; 光标指示字符位置,显存中一个字符占2字节,光标位置乘2得到该字符在显存中得偏移地址    mov [es:bx], clshr bx, 1       ; 恢复bxinc bx          ; 将光标推进到下一个位置; 判断是否需要向上滚动一行屏幕.roll_screen:cmp bx, 2000    ; 25行x80列jl .set_cursormov ax, 0xb800    mov ds, ax      ; movsw的源地址ds:simov es, ax      ; movsw的目的地址es:dimov si, 0xa0mov di, 0cld             ; 传送方向cls stdmov cx, 1920    ; rep次数 24行*每行80个字符*每个字符加显示属性占2字节 / 一个字为2字节rep movsw; 清除屏幕最底一行,即写入黑底白字的空白字符0x0720mov bx, 3840    ; 24行*每行80个字符*每个字符加显示属性占2字节mov cx, 80.cls:mov word [es:bx], 0x0720add bx, 2loop .clsmov bx, 1920    ; 重置光标位置为最底一行行首; 根据bx重置光标位置; 索引寄存器端口0x3d4,其索引值14(0x0e)和15(0x0f)分别用于提供光标位置的高和低8位; 数据端口0x3d5.set_cursor:mov dx, 0x3d4   mov al, 0x0e   out dx, almov dx, 0x3d5mov al, bh      ; in和out 只能用al或者axout dx, almov dx, 0x3d4mov al, 0x0fout dx, almov dx, 0x3d5mov al, blout dx, alpop espop dspop dxpop cxpop bxpop axretmy_int_0x70:push axpush bxpush cxpush dxpush es.w0:                                    mov al,0x0a                        ;阻断NMI。当然,通常是不必要的or al,0x80                          out 0x70,alin al,0x71                         ;读寄存器Atest al,0x80                       ;测试第7位UIP jnz .w0                            ;以上代码对于更新周期结束中断来说 ;是不必要的 xor al,alor al,0x80out 0x70,alin al,0x71                         ;读RTC当前时间(秒)push axmov al,2or al,0x80out 0x70,alin al,0x71                         ;读RTC当前时间(分)push axmov al,4or al,0x80out 0x70,alin al,0x71                         ;读RTC当前时间(时)push ax; 读一下RTC的寄存器C,使得所有中断标志复位。相当于,告诉RTC,中断已得到处理,可以继续下一次中断。; 否则,RTC看到中断未被处理,将不再产生中断信号。; RTC产生中断的原因有多种,可以在程序中通过读寄存器C来判断。不过,这里不需要,因为除了更新周期结束中断外,其他中断都被关闭了。mov al,0x0c                        ;寄存器C的索引。且开放NMI out 0x70,alin al,0x71                         ;读一下RTC的寄存器C,否则只发生一次中断;此处不考虑闹钟和周期性中断的情况 ; 屏幕是黑的,默认的显示属性是0x07,即黑底白字mov ax,0xb800mov es,ax                          ; es指向显示缓冲区mov bx,12*160 + 36*2               ;从屏幕上的12行36列开始显示    ; 小时pop axcall bcd_to_asciimov [es:bx],ahmov [es:bx+2],al                   ;显示两位小时数字mov byte [es:bx+4],':'             ;显示分隔符':'not byte [es:bx+5]                 ;反转显示属性 ; 分钟pop axcall bcd_to_asciimov [es:bx+6],ahmov [es:bx+8],al                   ;显示两位分钟数字mov al,':'mov [es:bx+10],al                  ;显示分隔符':'not byte [es:bx+11]                ;反转显示属性; 秒pop axcall bcd_to_asciimov [es:bx+12],ahmov [es:bx+14],al                  ;显示两位小时数字; 向8259芯片发送中断结束命令(End Of Interrupt, EOI)mov al,0x20                        ;中断结束命令EOI out 0xa0,al                        ;向从片发送 out 0x20,al                        ;向主片发送pop espop dxpop cxpop bxpop axiret        ; iret 中断返回指令,Interrupt Return,回到中断之前的地方继续执行; 这里如果用ret,显示的时间将不会更新 ? ? ?; Function: BCD码转ASCII
; Input: AL, BCD码
; Output: AX, ascii码
bcd_to_ascii:mov ah, al      ; 先复制到ah,用于后面处理十位数,al用于处理个位数and al, 0x0f    ; 仅保留低4位add al, 0x30    ; 转换成ASCIIshr ah, 4and ah, 0x0fadd ah, 0x30ret;===============================================================================
SECTION data align=16 vstart=0msg_init       db 'Starting...',0x0d,0x0a,0msg_install    db 'Installing a new interrupt 70H...',0msg_done       db 'Done.',0x0d,0x0a,0msg_tips       db 'Clock is now working.',0; ===============================================================================
SECTION stack align=16 vstart=0resb 256
stack_end:; ===============================================================================
SECTION program_tail
program_end:

[书]x86汇编语言:从实模式到保护模式 -- 第九章 硬中断,使用RTC芯片实现实时时间的显示;软中断,使用BIOS中断实现键盘输入的读取和显示相关推荐

  1. [书]x86汇编语言:从实模式到保护模式 -- 第13章 mbr加载内核、内核加载应用程序

    # mbr加载内核 1.0x7c00,16位实模式 2.进入保护模式前的准备工作:创建段描述符(代码段.数据段.堆栈段.显示缓冲区),构建gdt 3.进入保护模式 ; 开启保护模式 ; CR0的第1位 ...

  2. [书]x86汇编语言:从实模式到保护模式 -- 第17章 中断、任务切换、分页机制、平坦模型

    # 任务切换 内核任务.用户任务1.用户任务2,之前的轮询切换 利用RTC芯片的硬件中断来实现任务切换 计算机主板上有实时时钟芯片RTC,可以设置RTC芯片,使得它每次更新CMOS中的时间信息后,发出 ...

  3. [书]x86汇编语言:从实模式到保护模式 -- 第11章 进入保护模式,初识全局描述符表GDT; 第12章 别名,冒泡排序

    第11章 进入保护模式:初始化全局描述符表,通过GDT进入代码段.数据段.堆栈段 ; FILE: c11_mbr.asm ; DATE: 20191229 ; TITLE: 硬盘主引导扇区代码; 设置 ...

  4. [书]x86汇编语言:从实模式到保护模式 -- 第16章 分页机制、平坦模型

    # 分页机制 二级页表:页目录.页表 ==> 4KB物理页 32位线性地址中:高10位为页目录中的索引号(乘4得偏移量),该目录项指向页表的基地址:中间10位为页表中的索引号,该页表项指向4KB ...

  5. [书]x86汇编语言:从实模式到保护模式 -- 第15章 任务切换

    # 执行结果 # TODO:字符串显示函数的滚屏部分应该是有bug. # file_02: c15_core.asm ; FILE: c13_core.asm ; DATE: 20200104 ; T ...

  6. [书]x86汇编语言:从实模式到保护模式 -- 第14章 任务和特权级保护,调用门、LDT、TSS、TCB

    # 加载用户程序 Part 1.TCB, Task Control Block, 任务控制块 分配内存作为该任务的TCB,并插入至TCB链表. Part 2.LDT, Locak Descriptor ...

  7. [书]x86汇编语言:从实模式到保护模式 -- 第八章 硬盘和显卡的访问与控制,mbr加载并重定位应用程序

    第八章 硬盘和显卡的访问与控制 mbr加载.重定位用户程序 PART 1 >> VirtualBox显示最终效果 ===================================== ...

  8. [书]x86汇编语言:从实模式到保护模式 -- 第六、七章 编写主引导扇区代码

    第六章 编写主引导扇区代码(启动时显示文字:Label offset:) PART 1 >> 用VirtualBox显示最终效果 1.1 汇编 启用nasm的工具"nasm-sh ...

  9. 硬盘和显卡的访问与控制(一)——《x86汇编语言:从实模式到保护模式》读书笔记01

    本文是<x86汇编语言:从实模式到保护模式>(电子工业出版社)的读书实验笔记. 这篇文章我们先不分析代码,而是说一下在Bochs环境下如何看到实验结果. 需要的源码文件 第一个文件是加载程 ...

最新文章

  1. CVPR 2019 | 惊艳的SiamMask:开源快速同时进行目标跟踪与分割算法
  2. 我的Linux成长路---001 Linux学习初期计划
  3. HDU 1671 Phone List
  4. 【数理知识】《随机过程》方兆本老师-第6章-鞅过程及其性质
  5. 3.程序的局部性原理
  6. java sendmessage函数_vc中SendMessage自定义消息函数用法实例
  7. 高质量程序设计指南c++/c语言(25)--类与内联函数
  8. 开发小程序遇协同、平台兼容难题,该如何破局?
  9. 带有参数的输出存储过程
  10. 立创EDA封装命名规范参考
  11. html怎么添加视频链接,PPT怎么将超链接添加到视频图文教程
  12. Makefile 的解读(一)
  13. Pycharm, 生成可执行文件,Unhandled exception in script报错
  14. kong插件之Rate Limiting
  15. 查看oracle11g的企业管理器(OEM)
  16. swift 判断是否设置了代理
  17. cmake交叉编译mbedtls,open62541笔记
  18. Alignment trap
  19. 对短视频和技术的一些看法
  20. 点要素生成面要素(Arcgis实操系列)

热门文章

  1. 灰色关联度Python实现
  2. 08年中国最火的10大网上商店系统
  3. 小白学习shell命令---自学笔记
  4. 2019自考00018计算机应用基础,2018年4月自考00018计算机应用基础试题及答案
  5. 2021-07-11-gdF103替换st103
  6. 响应式图片img中的srcset和sizes
  7. 各路由器的用户名与密码
  8. android多国语言翻译包命名,android多国语言翻译工具,一键生成28国家翻译6666翻车了...
  9. Discuz教程之邮件找回密码邮件发送频率修改
  10. Portal官网上的介绍1什么是门户(Portal)?