由上一篇我们了解到汇编的一些DOS常用功能,并且我们通过9号功能显示出了一段存储了Hello World的字符串
这一次我们通过2号功能来创建一些简单的画面
在本篇中我们将引入子函数、堆栈的概念,以及如何用汇编来描写一个C语言的for循环
首先我们看一下DOS的2号功能
1 2 3 | MOV DL,3 MOV AH,2 INT 21H |
DOS的2号功能为显示输出,这里的DL是显示的字符的ASCII值
运行效果如下
接下来我们将改变这个❤的显示坐标点
将代码改为
1 2 3 4 5 6 7 8 | MOV DH,10 MOV DL,30;设置x坐标 MOV AH,2 INT 10h MOV DL,3;设置显示对象Ascii值 INT 21H |
如上图所示❤已经被移动到(30列,10行)的位置了,这里的DH表示行,DL表示列,INT 10h在这里的意思表示中断程序设置坐标,其他和上一步一样MOV DL,3 … MOV AH2
这里需要注意出现了两次DL,DL即DX的低位,DX本身不代表任何意义,仅仅是一个通用寄存器,不同的汇编操作会从不同的寄存器上读取参数,所以可能在同一代码段中出现数次同一寄存器的赋值但所代表含义却不一样。对于先学高级语言再学汇编的同学来说可能在学习初期会有些不适应。
接下来我们将这个打印功能封装成一个函数,类似C语言里的一个function,我们知道在C语言中一个函数的定义语法是
1 2 3 4 5 | void 函数名(){ 函数体; } |
在汇编中也与此相似
1 2 3 | 子函数名: 子函数内容 ret |
这里我们将之前的代码写成子程序合并后一起放出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | DATAS SEGMENT ;此处输入数据段代码 DATAS ENDS STACKS SEGMENT ;此处输入堆栈段代码 STACKS ENDS CODES SEGMENT ASSUME CS:CODES,DS:DATAS,SS:STACKS START: MOV AX,DATAS MOV DS,AX ;此处输入代码段代码 MOV DH,10 MOV DL,30;设置x坐标 call DRAW MOV AH,07 INT 21H DRAW: PUSH AX PUSH DX MOV AH,2 INT 10h MOV DL,3 INT 21H POP DX POP AX ret MOV AH,4CH INT 21H CODES ENDS END START |
运行效果与之前同图,接下来逐一说明一下我们新接触到的代码的含义
先从子函数来看,CALL就是对这个DROW函数的调用,而DROW和ret包围的部分就是这个子函数体
在子函数体中,我们看到了PUSH AX,PUSH DX,POP AX,POP DX这4个命令,这就是堆栈操作
对于堆栈的概念这里不再赘述,不懂的同学自己度娘一下
我们这里只解释一下为什么要在子函数体中进行这些堆栈操作:
在DROW子函数中,MOV AH,2 、MOV DL,3 分别对AX,DX这两个通用寄存器进行了修改,如果不把调用DROW前的AX,DX保存起来,DROW函数执行后,不管是后面的MOV AH,07 还是 MOV AH,4CH 都无法正取的表达其意思,故程序会出现错误。所以这里PUSH 先把这两个参数入栈,使用完毕后,把之前的值复原,即POP,这样就对程序后面的执行不造成影响。
就好比去邻居家借一个箱子(通用寄存器)来搬东西(DATA),箱子中已经有一些邻居的东西,我们就需要先挪出来(PUSH)放到一个特定的地方(栈),用完了再从特定的地方复原(POP)再还给邻居
MOV AH,01 眼尖的同学能够发现这是一张生面孔,其意义为等待键盘输入,有点类似C中的getchar()的意思,出现在这里的作用是为程序增加一个等待点,否则就一闪而逝看不到效果了。
接下来我们试着批量添加图案,首先了解一下在汇编里面是如何进行for循环的
1 2 3 4 | MOV CX,99 BeiTown ADD AX,1 LOOP BeiTown |
其意义表示成C
1 2 3 4 | for(int i=99;i>0;i--) { AX++; } |
这里的CX就相当于i,每进行一次循环,CX就会自减1,当CX为0时则循环结束,BeiTown在这里为一个代码段标记,标记Loop的返回点
现在我们再次把这些代码组合起来,循环显示一排❤看看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | DATAS SEGMENT ;此处输入数据段代码 DATAS ENDS STACKS SEGMENT ;此处输入堆栈段代码 STACKS ENDS CODES SEGMENT ASSUME CS:CODES,DS:DATAS,SS:STACKS START: MOV AX,DATAS MOV DS,AX ;此处输入代码段代码 MOV DH,10 MOV DL,30;设置x坐标 ;此处为循环开始 MOV CX,20 BeiTown: ADD DL,1;x坐标++ call DRAW LOOP BeiTown ;循环结束 MOV AH,01 INT 21H DRAW: PUSH AX PUSH DX MOV AH,2 INT 10h MOV DL,3 INT 21H POP DX POP AX ret MOV AH,4CH INT 21H CODES ENDS END START |
到这里本节就结束了,下一节我们将学习怎样通过键盘的控制让图形动起来,以此来进行一个交互性小游戏的制作,敬请期待
BeiTown
2012-11-26