王爽<汇编语言>课件设计
我是prolove_000,郁闷了,散分散太多了...变得不能发帖.
问题:
为什么debug不能调试呢?调试到mov ch,0就出现强制退出的状况...
assume cs:code,ds:data,ss:stackdata segment db '1975','1976','1977','1978','1979','1980','1981','1982','1983' db '1984','1985','1986','1987','1988','1989','1990','1991','1992' db '1993','1994','1995',0 dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514 dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000,0 dd 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226,11542,14430,15257,17800,0 dw 5,3,42,104,85,210,123,111,105,125,140,136,153,211,199,209,224,239,260,304,0data endsstack segment dw 8 dup(0)stack endscode segmentstart: mov ax,data mov ds,ax mov bx,0 mov ax,stack mov ss,ax mov sp,16 mov ax,0b8000h ;把显存地址放入ax寄存器中 mov es,ax ;再把ax中的显存地址放入es中 mov di,0 ;把di设置控制ds中的列 mov si,0 ;控制es的行 call pw mov ax,4c00h int 21h pw: push bx push di push si push cx push bx mov cl,[bx] ;把[bx]=0这个地址中的内容存放到cl中 mov ch,0 mov es:[si],cl ;把cl的内容存放到 jcxz pe mov dl,0A0h ;显存中一行有160个字节,所以存到cx中 mul dl ;因为一行有160个字节,所以乘以cx可以把光标定位到下一行 mov si,ax ; 把光标定位到下一行起始地址 inc bx inc si jmp short pwpe: mov si,0 ;把si光标从新定位到0这个位置 mov si,0ah ;把光标设定到第一行第10个字节处 mov dx,ds:[bx] ;把data段中定义的dword数据的高字节[bx]存放到dx中 mov ax,ds:[bx+4] ;把data段中定义的dword数据的低字节[bx+2]存放到ax中 mov cx,dx ;把dx中的内容扔到cx中 mov es:[si],cx ;把cx中的内容放到[si]处 mov cx,ax ;把把低字节ax放到cx处 mov es:[si+4],cx ;把cx中的内容放到[si+4]处 jcxz pb mov dl,0a0h ;显存中一行有160个字节,所以存到cx中 mul dl ;因为一行有160个字节,所以乘以cx可以把光标定位到下一行 mov si,ax ; 把光标定位到下一行起始地址 add bx,4 ;把ds中的光标定位到下一个地址 add si,4 ;把es中的光标定位到下一个地址 jmp short pe pb: mov si,0 mov si,1Dh ;把光标定位到第一行的29字节处 mov dx,ds:[bx] ;把data段中定义的dword数据的高字节[bx]存放到dx中 mov ax,ds:[bx+4] ;把data段中定义的dword数据的低字节[bx+2]存放到ax中 mov cx,dx ;把dx中的内容扔到cx中 mov es:[si],cx ;把cx中的内容放到[si]处 mov cx,ax ;把把低字节ax放到cx处 mov es:[si+4],cx ;把cx中的内容放到[si+4]处 jcxz pm mov dl,0a0h ;显存中一行有160个字节,所以存到cx中 mul dl ;因为一行有160个字节,所以乘以cx可以把光标定位到下一行 mov si,ax ; 把光标定位到下一行起始地址 add bx,4 ;把ds中的光标定位到下一个地址 add si,4 ;把es中的光标定位到下一个地址 jmp short pepm: mov si,0 mov si,25h mov cx,ds:[bx] mov es:[si],cx jcxz over mov dl,0a0h mul dl mov si,ax add bx,2 add si,2 jmp short pm over: pop bx pop ax pop bx pop di pop si pop cx retcode endsend start
把指向的位置设置成刚刚计算好的数据段的位置就行了。
其余可能还要多加些代码
下面是我以前做的,楼主可以参考下整个思路。
好了不早了,该睡了,明天第一天去学车。。。
assume cs:code , ds:data , ss:stack; 数据段data segment db '1975','1976','1977','1978','1979','1980','1981','1982','1983' ;第一个偏移值:0 db '1984','1985','1986','1987','1988','1989','1990','1991','1992' db '1993','1994','1995' ;最后一个偏移值:53H(83D) ;以上是表示21年的21个字符串 dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514 ;第一个偏移值:54H(84D) dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000 ;最后一个偏移值:A7H(167D) ;以上是表示21年公司总收入的21个dword型数据 dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226 ;第一个偏移值是:A8H(168D) dw 11542,14430,15257,17800 ;最后一个偏移值是:D2(210D) ;以上是表示21年公司雇员人数的21个word型数据 dw 64 dup(?) ; 因为最后转换成字符串的空间不够,所以需要再多申请这么多空间data ends; 栈段stack segment db 256 dup (?)stack ends; 计算后的数据存放段table segment db 21 dup ('year sunm ne ?? ') dw 32 dup(?) ; 因为最后转换成字符串的空间不够,所以需要再多申请这么多空间table ends; 代码段code segment start: ; 设置栈段地址 mov ax , stack mov ss , ax mov sp , 256 ; 计算数据段中的数据(计算人均收入,也就是收入除以雇员数) mov ax , data mov ds , ax mov bx , 0 call Calculate ; 循环,将双字节的数据的整型数转换成字符型 mov bx , 0 mov si , 0 ; 设置字符串输出的首地址 mov cx , 21 ; 设置循环次数 again: ; 复制年份到ds段 mov ax , es:[ bx ] mov ds:[ si ] , ax mov ax , es:[ bx + 2 ] mov ds:[ si + 2 ] , ax mov word ptr ds:[ si + 4 ] , 0 ; 存入0,表示间隔 add bx , 5 ; 因为只需跳过一个空格,空格占一个字节,再加上前面读取的4个字节 add si , 6 mov ax , es:[ bx ] ; 获取公司总收入的dword型数据的低位 mov dx , es:[ bx + 2 ]; ; 获取公司总收入的dword型数据的高位 call dtoc ; 调用子程序,将dword型数据转换成数字符串型,放到ds:si指定的位置 add bx , 5 ; 跳过已经读取的字节再加上一个空格 inc si ; 如果去掉这个自增1,则存放他们之间的间隔0为一个字节,没有去掉这个自增就为一个字 mov ax , es:[ bx ] ; 获取公司雇员人数的word型数据 mov dx , 0 ; 因为是word型数据,所以高位不需要,为0 call dtoc ; 调用子程序,将dword型数据转换成数字符串型,放到ds:si指定的位置 add bx , 3 ; 跳过已经读取的字节再加上一个空格 inc si ; 如果去掉这个自增1,则存放他们之间的间隔0为一个字节,没有去掉这个自增就为一个字 mov ax , es:[ bx ] ; 获取公司雇员的人均收入 mov dx , 0 ; 因为是word型数据,所以高位不需要,为0 call dtoc ; 调用子程序,将dword型数据转换成数字符串型,放到ds:si指定的位置 add bx , 3 ; 跳过已经读取的字节再加上一个空格 inc si ; 如果去掉这个自增1,则存放他们之间的间隔0为一个字节,没有去掉这个自增就为一个字 loop again ; 循环,用于显示所有的字符串 mov dh , 0 ; 第0行 mov dl , 2 ; 第2列 mov si , 0 ; 设置指向字符串首地址偏移量 mov cx , 22 ; 外循环共循环21次(因为第一次为了直接跳到循环处而一次性执行循环,所以需要多加一次循环) jmp show_start ; 跳到开始出,以便能直接使用loop循环一次性输出 show_again1: push cx ; 现场保护 mov cx , 4 ; 内循环共循环4次 show_again2: push cx ; 因为CX还要用来设置颜色,所以还要保护 mov ch , 0 mov cl , 01h ; 设置颜色(蓝色) call show_str add si , 2 ; 加上间隔符,进行下一组字符串的输出 add dl , 10 ; 每输出一串字符列就空开几列 pop cx ; 恢复内循环的循环次数值 loop show_again2 add dh , 1 ; 输出完一组就要换下一行 mov dl , 2 ; 输出完一组列就要归位 pop cx ; 恢复外循环的循环次数值show_start: loop show_again1 ; 结束程序 mov ax , 4c00h int 21h; 子程序; 计算数据段中的数据(计算平均收入,也就是收入除以雇员数); 入口参数:ds:bx为待计算的数据段; 出口参数:计算好后的数据将放在table数据段中,也可以用 es:0 来直接获取这个table数据段的首地址Calculate: mov ax , table mov es , ax ;设置要写入数据的段寄存器 mov bp , 0 ;设置table段的偏移地址 mov di , 0 ;设置雇员数每次增加的值(因为与其他值相比只有雇员数是2字节,所以要做特殊处理) mov cx , 21 ;设置循环的值为21次 again_1: mov ax , ds:[bx] ;复制年份的低字 mov es:[bp] , ax mov ax , ds:[bx + 2] ;复制年份的高字 mov es:[bp + 2] , ax mov ax , ds:0A8H.[di] ;复制雇员数(十进制168) mov es:[bp + 0AH] , ax ;加10是因为复制了2个字节,而且写入的时候要输入一个空格, ;并且这个位置是在复制了4个字节后的再加5个字节的位置 mov ax , ds:54H.[bx] ;复制收入的低字节(十进制84) mov es:[bp + 5] , ax mov dx , ds:54H.[bx + 2] ;复制收入的高字节(十进制84) mov es:[bp + 7] , dx div word ptr ds:0A8H.[di] ;因为除数是2个字节(16位)的,所以也用di(di每次循环增加2) mov es:[bp + 0DH] , ax ;复制算好的人均收入 add bp , 16 ;进行下一组写入 add di , 2 ;用于计算雇员数的值加2,因为他一次值复制了2个字节 add bx , 4 ;复制了一次后要加上4字节,以便下一次读出和计算 loop again_1 ret ; Calculate子程序返回;参数: (ax) = dword型数据的低16位; (dx) = dword型数据的高16位; (cx) = 除数;返回: (dx) = 结果的高16位; (ax) = 结果的低16位; (cx) = 余数divdw: ;子程序定义开始 push ax mov ax,dx mov dx,0 div cx mov bx,ax pop ax div cx mov cx,dx mov dx,bx ret ;子程序定义结束; 功能:将dword型数据转变为表示十进制数的字符,字符以0为结尾符; 参数:(ax) = dword型数据的低16位; (dx) = dword型数据的高16位; ds:si指向字符串的首地址; 返回:无 dtoc: push cx ; 保护现场 push bx ; 保护现场 push si ; 保存用来输出结果的字符串的首地址 mov byte ptr ds:[ si ] , 0 ;先写入结束符(写在首位,以便配合栈结构) inc si mov cx , 1again_3:mov cx , 10 ; 做除数,每次都除以10,以便得到余数,从而求出每个位的值 call divdw ; 调用除法子程序,因为这个除法子程序可以防止数据溢出 add cl , 30H ;加上30H成为字符的ASCII码 mov ds:[ si ] , cl ;存入到指定的数据段 ; 判断商的低位和高位是否都为0如果都为0,则表示结束 mov cx , 0 or cx , ax or cx , dx jcxz ok1 inc si inc cx ;因为loop会将cx减少1,所以要先加1 loop again_3 ok1: mov byte ptr ds:[ si + 1 ] , 0 ;尾部也写入结束符 pop si ; 取出用来输出结果的首地址 mov bx , si ; bx用来做最后的数据存入,所以也是为输出结果的首地址 mov al , ds:[ si ] ;从得到的第一个数据开始遍历 mov ah , 0 ;只要低位,高位归零 push ax ;结束符先入栈 ;把得出的字符倒过来,因为求余得到的数是倒着的again_4:inc si mov al , ds:[ si ] mov ah , 0 ;只要低位,高位归零 mov cx , ax jcxz ok2 ;已经全部临时存入栈中 push ax inc cx ;因为loop会将cx减少1,所以要先加1 loop again_4 ok2: pop cx ;从栈中取出,正好实现倒叙 mov ds:[ bx ] , cl ;只要低位,高位归零 jcxz return inc bx inc cx ;因为loop会将cx减少1,所以要先加1 loop ok2return: pop bx ; 恢复现场 pop cx ; 恢复现场 ret ; 返回;子程序;功能:在指定的位置 , 用指定的颜色 , 显示一个用0结束的字符串;参数:(dh) = 行号(取值范围0~24) , (dl) = 列号(取值范围0~79); (cl) = 颜色 , ds:si指向字符串首地址show_str: push dx ; 现场保护 mov ax , 000ah ;转换成行需要乘以a(10) mul dh ;计算写入位置的行 add ax , 0b800h ;B800是起始位置,所以加上规定的行数 add dl , dl ;计算写入位置的列 mov dh , 0 mov es , ax ;设置写入位置的寄存器 mov di , dx mov al , cl ;保存颜色 mov cx , 2 jmp first_start again_2: mov cl , ds:[si] ;获取要显示的数据 mov ch , 0 ;不需要高位 jcxz ok ;如果是0则返回(结束这个子程序) mov es:[di] , cl ;将字符写入 mov es:[di + 1] , al ;写入颜色 add di , 2 ;指向下一个要写入的位置 inc si ;指向下一个要读取字符的位置 mov cl , 2 ;again循环每次都成立first_start: loop again_2ok: pop dx ; 恢复 ret ;返回(结束)这个子程序code endsend start