写个dos弹球小动画

前段时间把汇编复习了一遍,心里感觉踏实多了。。。最近一直在看数电和数据结构,结果好像用眼过度了,老毛病又犯了,只能连着休息了两天,没敢用电脑。今天刚打开计算机也不知道干什么,就写个简陋的dos动画吧,纯属练练手。
一个碰到四壁会反弹的小球,纯dos下可以看到闪烁的效果,v86自然就木有闪烁了。其实进一步编写应该可以写出一个小游戏来,不(但)过(是)考(我)虑(是)的(个)东(水)西(平)就(很)比(次)较(的)多(渣)了(啊)。
下面是源码:

递归与可重入子程序

递归:
示例:计算阶乘(n<=8)
入口参数:ax=n
出口参数:ax=n!
fact proc
push dx ;每次都要保存dx的值,即n的值,否则在返回上一层时,dx的值错误
mov dx,ax
cmp ax,0
jz ok
dec ax ;n=n-1
call fact ;计算(n-1)!
mul dx ;n*(n-1)!=n!
pop dx
ret
ok: mov ax,1
ret
fact endp

键盘输入与显示笔记

关于直接定址表部分事实上能做的笔记较少,只能多看书,多写代码巩固用法。就不写笔记了。
1.cpu执行完int9之后,键盘输入放到了键盘缓冲区中。
2.键盘缓冲区有16个字单元,可以存储15个按键的扫描码和对应的ascii码
3.只有通码及相应ascii码会放入键盘缓冲区,断码不会。
4.一个按键占一个字,高位字节放扫描码,低位字节放ascii码
5.控制键(shift、ctrl等)不会放入键盘缓冲区,但会改变状态字节的对应位(具体见上上篇笔记)
6.int 16h
ah=0
从键盘缓冲区读取一个键盘输入
返回:ah=扫描码,al=ascii码
7.调用int 16h的0号功能后,已读取的键盘输入从缓冲区删除。
8.如果键盘缓冲区为空,则调用int 16h的0号功能会循环等待,直到有数据。
9.字符串的输入显示、删除、回车结束等是利用栈来实现的。
最近心情有些沮丧,没有写代码的欲望了,下次再写相关程序吧。
王爽的汇编入门书到这里终于算是复习完毕了。。接下来就是大量练习巩固了。

外中断笔记2

重写int9中断
目标:按下F1键改变屏幕颜色
这个程序没有运行过,因为要访问真实的硬件,必须在纯dos下运行,而我试了好久发现把exe文件加入dos7.1的虚拟磁盘文件中还是无法访问。。
这种改写中断的方式让我想到了windows编程中的api hook,api hook其中一种实现方式就是改掉api的开头几个字节,实现跳转。很像,有木有。。

外中断笔记1

1.cpu——端口(外部寄存器)——外设芯片——外设硬件
2.外中断源:
(1)可屏蔽中断:
如果if=1,则响应中断
如果if=0,则不响应中断
与内中断的不同点:中断类型码通过数据线传入
设置if位的指令:sti        cli
(2)不可屏蔽中断:
中断类型码固定为2
与内中断的不同点:不用取中断类型码
3.谁发出外中断的问题:中断由各芯片(主板上的,不是外设硬件中的)发出
4.pc机键盘(个人认为就是矩阵键盘+扫描处理程序,即可以用单片机实现)的处理过程:
(1)键盘中的芯片对每个键的状态进行扫描
(2)按下一个键,开关接通,芯片产生扫描码,扫描码说明按键位置。
(3)扫描码被送入主板相关接口芯片的寄存器中,端口地址:60h
(4)松开按键,也产生扫描码,也送入60h
(5)扫描码长度1字节
通码:按下时的扫描码,第七位为0
断码:松开时的扫描码,第七位为1
断码=通码+80h
(6)int 9
是bios中断
主要工作:
<1>读出60h的扫描码
<2>如果是字符键的扫描码,则将扫描码和相应ascii码送入内存中的bios键盘缓冲区。
如果是控制键,则转换为状态字节,写入内存中0040:17字节单元
*关于键盘缓冲区:可存储15个键盘输入,一个键盘输入用一个字,低位字节ascii码,高位字节扫描码。
*0040:17信息:

端口操作笔记与实验14,求优化。。

1.注意8086的内存与内存地址空间的区别:
内存:主存
内存地址空间:各种存储器和cpu的地址、数据及控制线相连,cpu操控时把它们当做内存对待,总的看成一个逻辑存储器。
2.端口实际上是各个芯片中的寄存器,cpu对它们统一编址。
3.cpu可以直接读写地方:
(1)cpu内部寄存器
(2)内存单元
(3)端口
4.cpu最多定位64KB个端口,端口地址范围:0——65535
5.端口读写必须用in、out指令
6.在in和out指令中,只能用ax或al来存放从端口读入的数据或要发送到端口中的数据
7.8位端口用al,16位端口用ax
8.对0——255以内端口读写:端口号用立即数
对256——65535的端口读写:端口号放dx中
9.cmos ram芯片
简称cmos
(1)包含一个实时钟,和128个存储单元的ram存储器
(2)电池供电,
(3)128个字节中,0——0dh:实时钟的时间信息。其余:系统配置信息
(4)两个端口:70h是地址端口,存放要访问的coms ram单元的地址。71h是数据端口,存放要读取或写入的数据。
(5)coms ram中的时间信息:
秒:0 分:2 时:4 日:7 月:8 年:9
这些数据以BCD码存放
每个信息用1个字节(两个BCD码,即两位十进制数),高四位表示十位,低四位表示个位。
10.通过上述知识点的总结,本人突然理清了以前一直比较模糊的问题。
关于cmos和bios:
(1)cmos里是ram,bios里是rom
(2)cmos只存数据,bios存程序
(3)开机进入bios,看到的是bios rom中的软件程序(此时已装入内存)。里面的参数就是cmos ram中的数据,通过bios中的程序设置cmos中的信息。

int指令笔记

1.进入中断例程后ds没有变,所以可以正确索引程序数据
2.进入中断例程后,通过修改栈中的ip值可以使返回到指定位置
3.bios中的内容:
(1)硬件系统的检测和初始化程序
(2)外部中断和内部中断例程
(3)用于对硬件设备进行I/O操作的中断例程
(4)其他和硬件系统有关的中断例程
4.在和硬件设备有关的dos中断例程中,一般都调用了bios的中断例程
5.bios和dos提供的中断例程如何安装到内存:
(1)开机,cpu加电,初始化cs=0ffffh,ip=0,自动从ffff:0处开始执行。ffff:0处有一条跳转指令,转去执行bios中的硬件系统检测和初始化程序。
(2)初始化程序建立bios的中断向量(注册)。
注意点:对于bios中断,只需注册,不用安装。因为在ROM中,一直在内存。
(3)int 19h 进行操作系统的引导(控制权转交OS)
(4)dos启动后,安装dos中断例程,并注册。
6.bios中断:
int 10h
(1)ah=2    设置光标
bh    页号
dh    行号
dl    列号
(2)ah=9    在光标处显示字符
al    字符
bl    颜色属性
bh    页号
cx    字符重复个数
7.dos中断:
int 21h
(1)ah=4ch    程序返回
al    返回值
(2)ah=9    在光标处显示字串
ds:dx    指向字符串(字符串用’$'结束)
注意:如果字符串过长,会自动换行;到了最后一行,会自动上卷。
8.写个7ch中断,显示用0结束的字符串。dh=行号,dl=列号,cl=颜色,ds:si指向字符串
程序功能非常简单,代码思路也很清晰,不再加注释
assume cs:code
code segment
start:
mov ax,cs
mov ds,ax
mov si,offset show
mov ax,0
mov es,ax
mov di,200h
mov cx,offset showend-offset show
cld
rep movsb

内中断笔记

0.操作数可以是表达式(如mov ax,(4+7/2)*5)
1.内中断源于cpu内部
2.下列情况产生内中断:
(1)除法错误(除法溢出)
(2)单步执行
(3)执行into指令
(4)执行int指令
3.中断类型码标识中断来源,为1个字节,可表示256种中断
上述中断的类型码:
(1)除法错误:0
(2)单步执行:1
(3)执行into指令:4
(4)执行int指令:int n   n是字节型立即数,为中断类型码
4.中断向量:中断处理程序的入口地址
5.中断向量表:0000:0000——0000:03ff,共1024个字节(256种*4byte/种)
6.一个中断向量为4字节,高字为cs,低字为ip。
7.中断过程:(由硬件完成)
(1)取得中断类型码n
(2)pushf
(3)TF=0,IF=0
(4)push cs
(5)push ip
(6)(ip)=(n*4),(cs)=(n*4+2)
8.中断处理程序:
(1)保存用到的寄存器
(2)处理中断
(3)恢复用到的寄存器
(4)iret返回
iret等效指令:
pop ip
pop cs
popf
9.中断向量表中0000:0200——0000:02ff的256个字节为空,可用于放代码和数据
10.下面给出重写0号中断的程序:
assume cs:code
code segment
start:
;;;;;;;;;;;;;;;;;;;安装
mov ax,cs
mov ds,ax
mov ax,0
mov es,ax
mov si,offset do0
mov di,200h
mov cx,offset do0end-do0    ;计算代码长度

df位、串传送

昨天高中同学会,今天白天又有事,所以决定把标志寄存器这章结束掉,下面是串操作笔记
movsb:
传送一个字节
相当于:
(1) ((es)*16+di)=((ds)*16+si)
(2) df=0 (si)=(si)+1
(di)=(di)+1
df=1 (si)=(si)-1
(di)=(di)-1
movsw:
传送一个字
rep movsb相当于:
s:movsb
loop s
可见rep是根据cx进行循环的

adc sbb cmp与条件转移

1.adc和sbb是带进(借)位加减法,理论上可以实现任意长度数据加减法
下面是示例:
assume cs:code,ds:data
data segment
dw    1122h,3344h,5566h,7788h
dw    1020h,3040h,5060h,7080h
data ends
code segment
start:
mov ax,data
mov ds,ax
xor si,si
mov di,8
mov cx,4