21,458
社区成员
发帖
与我相关
我的任务
分享
assume cs:code,ds:data,ss:stack
data 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,0
data ends
stack segment
dw 8 dup(0)
stack ends
code segment
start: 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 pw
pe: 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 pe
pm: 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
ret
code ends
end 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 , 1
again_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 ok2
return: 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_2
ok: pop dx ; 恢复
ret ;返回(结束)这个子程序
code ends
end 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',0 ;最后一个偏移值:53H(83D)
;以上是表示21年的21个字符串
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,data
mov ds,ax
;定义数据段
mov ax,stack
mov ss,ax
mov sp,256
;定义栈段
mov ax,table
mov es,ax
;定义附加段
mov si,0
mov di,0
mov bx,0
;初始化变址寄存器
mov dh,8 ;8行
mov dl,3 ;3列
mov cl,2 ;绿色
;定义颜色和行列
call show_ys
;调用子程序show_ys
mov ax,4c00h
int 21h
;子程序:show_ys
;功能:在指定的位置 , 用指定的颜色 , 显示一个用0结束的字符串
;参数:(dh) = 行号(取值范围0~24) , (dl) = 列号(取值范围0~79)
; (cl) = 颜色 , ds:si指向字符串首地址
show_ys:
push si
;保护数据
dec dh
;因为计算机是从0开始读取的,所以这里要-1
mov al,0A0h
;因为一行有160个字符,而换算16进制=0A0H
mul dh
;乘完之后,ax中现在存放的是行的偏移地址
mov si,ax
;把行复制给si
mov al,2
;因为一个字符要存放2个字节,高字节存放颜色,低字节存放数据
mul dl
;而这么乘完就知道了列数,而列数存放在ax中
sub ax,2
;因为ax现在存放是列数,而一个字符要放2个字节,所以要把光标定位到0(偶字节)
add si,ax
;此时si中存放的是行与列的偏移地址
mov ax,0b800h
mov es,ax
;把es段地址定义出来
mov al,cl
;把颜色存放到al中
mov ch,0
s:
mov cl,ds:[bx]
;把数据段的内容复制到cl中
jcxz ok
;如果数据段中的那个0字符存放到
mov es:[si],al
;把颜色存放到显存中存放字符串的高字节,也就是存放颜色的位置
mov es:[si+1],cl
;把数据段的内容放到显存存放字符串的低字节,也就是存放数据的位置
add si,2
;把显存的光标定位到第二个存放颜色的位置
inc bx
;把DS中的光标定位到下一个字节处
jmp short s
;循环中
ok:
pop si
ret
;子程序:divdw
;公式:X/N=int(H/N)*65536+[rem(H/N)*65536+L]/N
;divdw:
; push ax ;保存低16位数
; mov ax,dx ;把高16位放到ax中
code ends
end 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个字符串
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,data
mov ds,ax
;定义数据段
mov ax,stack
mov ss,ax
mov sp,256
;定义栈段
mov ax,table
mov es,ax
;定义附加段
mov si,0
mov di,0
mov bx,0
;初始化变址寄存器
mov cx,21
s: mov al,ds:[bx] ;把数据段的bx中的数据存入al
mov es:[si],al
add bx,1
add si,0A0h
add si,1
call show_ys
loop s
mov ax,4c00h
int 21h
;子程序:show_ys
;功能:在指定的位置 , 用指定的颜色 , 显示一个用0结束的字符串
;参数:(dh) = 行号(取值范围0~24) , (dl) = 列号(取值范围0~79)
; (cl) = 颜色 , ds:si指向字符串首地址
show_ys:
push si
;保存主程序可能用到的寄存器
mov ax,0b800h
mov es,ax
;把es段分配到显存地址中
mov al,2h
;颜色存放在al中
mov es:[si+1],al
;向es:[si+1]处写入颜色数据,也就是在奇地址中写入
pop si
;还原si寄存器原数据
ret
;子程序:divdw
;公式:X/N=int(H/N)*65536+[rem(H/N)*65536+L]/N
;divdw:
; push ax ;保存低16位数
; mov ax,dx ;把高16位放到ax中
code ends
end start