硬件方向个人札记(part 1)
分类:硬件方向个人札记日期:2012-02-28作者:SimolluS Heinz阅读:643 views
晚上有点懒得看书了,于是决定发一篇文总结一下今天所学的内容,同时作为对第一篇行数破百汇编源程序圆满完成的献礼~
长话短说,这个程序的任务要求在书197页下方,也就是实验十的第三部分,要求编程将123,12666,1,8,3,38这六个分别占据一字空间的数字以十进制字符的形式打印到屏幕上,打印的三个参数(行数,列数,属性)在源程序中给出。题目中给出编程指导并要求分别写成子程序模块:
(1)将用二进制信息存储的数据转变为十进制形式的字符串
(2)显示十进制的字符串
长话短说,直接发程序:
初始化代码区(CODESG),数据区(DATASG),额外数据区(ELSESG),堆栈区(STACKSG);这里需要提及一点,在书上所给的程序头之中是将六个数据直接放到DS区的,但如果这样的话,由于之后还要开辟空白空间放置转换后的字符,内存的定位只得使用【BX+SI+Idata】或类似格式,这不但使得定位语句难以书写,而且更多次地使用了本就将使用许多次的BX寄存器,导致普通寄存器的分配愈发复杂,通过堆栈有序储存数据的难度也随之加大,以至于可能不得不使用其他的内存空间储存中间值;但与造成了这么多的麻烦相反的是,段寄存器ES完全是闲置的,程序整体运行效率将随之下降。综上,决定利用ES有效定位原始数据,同时在程序中申请了专用的足量堆栈空间,防止运行错误;以下继续:
没什么可说的,初始化寄存器指向,其实既然之前在最初已经定位过寄存器位置(参见代码第一行),这一步骤可有可无,只是保险起见还是处理一下吧。但要注意堆栈段寄存器(SS)与偏移地址寄存器(SP)是必须在这一步初始化的,以做到将SP置于堆栈末尾。
以上为主程序部分,LOOP S1之前为利用六次循环调用子程序DTOC将六个二进制数转换为字符串,注意前半部分中利用两次SI寄存器:外圈用来表示源字符串的偏移地址,内圈清零进入子程序,作用后议;利用两次CX寄存器,外圈用来确定循环次数(6),内圈进入子程序,作用后议。同时对称使用PUSH与POP命令达到寄存外圈数据的目的。LOOP S1之后为调用SHOW_STR子程序达成显示数据的目的,DH,DL,CL寄存器分别存放行数,列数与属性。最后两行命令自然是结束程序返回SHELL。
此段为DTOC子程序,注意起初AX寄存器内为源数据,赋值到CX中以利用JCXZ命令跳出此后循环部分,具体方法为使用16位除法,被除数高位DX赋0,低位为AX(即源数据),与10相除后的余数(DX中的值)即为反向输出的数字,依此类推直到商为零,除法运算次数通过SI寄存器存储下备用:
例:123除以10,余数分别为3,2,1;共循环3次达到商为0.
注意此时字符顺序是反的,故利用堆栈调转顺序,循环次数即为之前所存下的SI值;同时此时的字符还不是ASCII码表示法,应该分别加上30H转化为数字对应的标准码并存入DS:【0】起始的空间。最后RET返回。
此段为SHOW_STR子程序,负责向屏幕输出内存DS:【0H】起的内容直到内存空间中字符为空为止。首先初始化ES寄存器指向显示缓冲区,注意此时将要写入的数据已存于DS空间,ES段寄存器所确定的源数据事实上已无用,所以可以直接修改其指向位置以便于随后利用。随后利用(行数*160+列数*2)公式确定写入数据位置,应知显示寄存器中数据在偶数位,属性在奇数位,所以此公式直接指向正确位置无需加一。之后循环写入数据与属性(以BX定位),最后RET返回主程序,注意此时的SI已经是主程序外圈变量清零而成的专用计数器。
至此程序圆满结束,显示效果如下:
显然在这一显示结果中尚存一个小问题,即各个数据间没有空位分割导致难以分划。由于这可以通过寄存器修改内存数据,或是在主程序循环写入内存的各个命令间写入空白位的方法轻易解决,故不再赘述。
源程序编写完成,凡102行,作为第一次写下的行数超过百行的汇编代码,倒也确实值得如此这般详加分析,以咨留念。
特此
暂时没有评论!