汇编代码

  1 assume cs:code , ds:data , ss:stack
  2 
  3 ; 数据段
  4 data segment
  5 
  6         db '1975','1976','1977','1978','1979','1980','1981','1982','1983'    ;第一个偏移值:0
  7 
  8         db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
  9 
 10         db '1993','1994','1995'        ;最后一个偏移值:53H(83D)
 11 
 12         ;以上是表示21年的21个字符串
 13 
 14  
 15 
 16         dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514        ;第一个偏移值:54H(84D)
 17 
 18         dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000        ;最后一个偏移值:A7H(167D)
 19 
 20         ;以上是表示21年公司总收入的21个dword型数据
 21 
 22  
 23 
 24         dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226        ;第一个偏移值是:A8H(168D)
 25 
 26         dw 11542,14430,15257,17800                                                    ;最后一个偏移值是:D2(210D)
 27 
 28         ;以上是表示21年公司雇员人数的21个word型数据
 29 
 30     dw 64 dup(?)        ; 因为最后转换成字符串的空间不够,所以需要再多申请这么多空间
 31 
 32 data ends
 33 
 34 
 35 
 36 ; 栈段
 37 stack segment
 38 
 39     db 256 dup (?)
 40 
 41 stack ends
 42 
 43 
 44 ; 计算后的数据存放段
 45 table segment
 46 
 47         db 21 dup ('year sunm ne ?? ')
 48 
 49     dw 32 dup(?)        ; 因为最后转换成字符串的空间不够,所以需要再多申请这么多空间
 50 
 51 table ends
 52 
 53 
 54 
 55 ; 代码段
 56 code segment
 57 
 58  start:
 59 
 60     ; 设置栈段地址
 61     mov ax , stack
 62     mov ss , ax
 63     mov sp , 256
 64 
 65 
 66 
 67     ; 计算数据段中的数据(计算人均收入,也就是收入除以雇员数)
 68     mov ax , data
 69     mov ds , ax
 70     mov bx , 0
 71     call Calculate
 72 
 73 
 74 
 75 
 76     ; 循环,将双字节的数据的整型数转换成字符型
 77     mov bx , 0
 78     mov si , 0            ; 设置字符串输出的首地址
 79     mov cx , 21            ; 设置循环次数
 80  again: 
 81     ; 复制年份到ds段
 82     mov ax , es:[ bx ]
 83     mov ds:[ si ] , ax
 84     mov ax , es:[ bx + 2 ]
 85     mov ds:[ si + 2 ] , ax
 86     mov word ptr ds:[ si + 4 ] , 0    ; 存入0,表示间隔
 87     add bx , 5            ; 因为只需跳过一个空格,空格占一个字节,再加上前面读取的4个字节
 88     add si , 6
 89 
 90 
 91     mov ax , es:[ bx ]        ; 获取公司总收入的dword型数据的低位
 92     mov dx , es:[ bx + 2 ];        ; 获取公司总收入的dword型数据的高位
 93     call dtoc            ; 调用子程序,将dword型数据转换成数字符串型,放到ds:si指定的位置
 94     add bx , 5            ; 跳过已经读取的字节再加上一个空格
 95     inc si                ; 如果去掉这个自增1,则存放他们之间的间隔0为一个字节,没有去掉这个自增就为一个字
 96 
 97     mov ax , es:[ bx ]        ; 获取公司雇员人数的word型数据
 98     mov dx , 0            ; 因为是word型数据,所以高位不需要,为0
 99     call dtoc            ; 调用子程序,将dword型数据转换成数字符串型,放到ds:si指定的位置
100     add bx , 3            ; 跳过已经读取的字节再加上一个空格
101     inc si                ; 如果去掉这个自增1,则存放他们之间的间隔0为一个字节,没有去掉这个自增就为一个字
102 
103     mov ax , es:[ bx ]        ; 获取公司雇员的人均收入
104     mov dx , 0            ; 因为是word型数据,所以高位不需要,为0
105     call dtoc            ; 调用子程序,将dword型数据转换成数字符串型,放到ds:si指定的位置
106     add bx , 3            ; 跳过已经读取的字节再加上一个空格
107     inc si                ; 如果去掉这个自增1,则存放他们之间的间隔0为一个字节,没有去掉这个自增就为一个字
108 
109   loop again
110 
111 
112 
113     ; 循环,用于显示所有的字符串
114     mov dh , 0            ; 第0行
115     mov dl , 2            ; 第2列
116     mov si , 0            ; 设置指向字符串首地址偏移量
117     mov cx , 22            ; 外循环共循环21次(因为第一次为了直接跳到循环处而一次性执行循环,所以需要多加一次循环)
118 
119     jmp show_start            ; 跳到开始出,以便能直接使用loop循环一次性输出
120 
121  show_again1:
122 
123     push cx                ; 现场保护
124     mov cx , 4            ; 内循环共循环4次
125 
126    show_again2:
127 
128     push cx                ; 因为CX还要用来设置颜色,所以还要保护
129     mov ch , 0
130     mov cl , 01h            ; 设置颜色(蓝色)
131     call show_str
132     add si , 2            ; 加上间隔符,进行下一组字符串的输出
133     add dl , 10            ; 每输出一串字符列就空开几列
134     pop cx                ; 恢复内循环的循环次数值
135 
136    loop show_again2
137 
138     add dh , 1            ; 输出完一组就要换下一行
139     mov dl , 2            ; 输出完一组列就要归位
140     pop cx                ; 恢复外循环的循环次数值
141 show_start:
142  loop show_again1
143 
144 
145 
146     ; 结束程序
147     mov ax , 4c00h
148     int 21h
149 
150 
151 
152 ; 子程序
153 ; 计算数据段中的数据(计算平均收入,也就是收入除以雇员数)
154 ; 入口参数:ds:bx为待计算的数据段
155 ; 出口参数:计算好后的数据将放在table数据段中,也可以用 es:0 来直接获取这个table数据段的首地址
156 Calculate:
157 
158         mov ax , table
159         mov es , ax            ;设置要写入数据的段寄存器
160 
161         mov bp , 0            ;设置table段的偏移地址
162 
163         mov di , 0            ;设置雇员数每次增加的值(因为与其他值相比只有雇员数是2字节,所以要做特殊处理)
164 
165         mov cx , 21            ;设置循环的值为21次
166 
167     again_1:
168         
169         mov ax , ds:[bx]        ;复制年份的低字
170         mov es:[bp] , ax
171 
172         mov ax , ds:[bx + 2]        ;复制年份的高字
173         mov es:[bp + 2] , ax
174 
175 
176 
177         mov ax , ds:0A8H.[di]        ;复制雇员数(十进制168)
178 
179         mov es:[bp + 0AH] , ax        ;加10是因为复制了2个字节,而且写入的时候要输入一个空格,
180                                     ;并且这个位置是在复制了4个字节后的再加5个字节的位置
181 
182 
183         mov ax , ds:54H.[bx]        ;复制收入的低字节(十进制84)
184         mov es:[bp + 5] , ax
185 
186         mov dx , ds:54H.[bx + 2]    ;复制收入的高字节(十进制84)
187         mov es:[bp + 7] , dx
188 
189 
190 
191         div word ptr ds:0A8H.[di]    ;因为除数是2个字节(16位)的,所以也用di(di每次循环增加2)
192 
193         mov es:[bp + 0DH] , ax        ;复制算好的人均收入
194 
195 
196 
197         add bp , 16        ;进行下一组写入
198 
199         add di , 2        ;用于计算雇员数的值加2,因为他一次值复制了2个字节
200 
201         add bx , 4        ;复制了一次后要加上4字节,以便下一次读出和计算
202 
203     loop again_1
204 
205   ret                    ; Calculate子程序返回
206 
207 
208 
209 
210 ;参数: (ax) = dword型数据的低16位
211 ;      (dx) = dword型数据的高16位
212 ;      (cx) = 除数
213 ;返回: (dx) = 结果的高16位
214 ;      (ax) = 结果的低16位
215 ;      (cx) = 余数
216 divdw:  ;子程序定义开始
217 
218         push ax
219 
220         mov ax,dx
221 
222         mov dx,0
223 
224         div cx
225 
226         mov bx,ax
227 
228         pop ax
229 
230         div cx
231 
232         mov cx,dx
233 
234         mov dx,bx
235 
236         ret   ;子程序定义结束
237 
238 
239 
240 
241 ; 功能:将dword型数据转变为表示十进制数的字符,字符以0为结尾符
242 ; 参数:(ax) = dword型数据的低16位
243 ;      (dx) = dword型数据的高16位
244 ;      ds:si指向字符串的首地址
245 ; 返回:无
246   dtoc: push cx                ; 保护现场
247     push bx                ; 保护现场
248     push si                ; 保存用来输出结果的字符串的首地址
249 
250     mov byte ptr ds:[ si ] , 0    ;先写入结束符(写在首位,以便配合栈结构)
251 
252     inc si
253 
254     mov cx , 1
255 
256 again_3:mov cx , 10            ; 做除数,每次都除以10,以便得到余数,从而求出每个位的值
257 
258     call divdw            ; 调用除法子程序,因为这个除法子程序可以防止数据溢出
259 
260     add cl , 30H            ;加上30H成为字符的ASCII码
261 
262     mov ds:[ si ] , cl        ;存入到指定的数据段
263 
264 
265     ; 判断商的低位和高位是否都为0如果都为0,则表示结束
266     mov cx , 0
267     or cx , ax
268     or cx , dx
269 
270     jcxz ok1
271 
272     inc si
273     inc cx                ;因为loop会将cx减少1,所以要先加1
274 
275     loop again_3
276 
277  ok1:   mov byte ptr ds:[ si + 1 ] , 0    ;尾部也写入结束符
278 
279     pop si                ; 取出用来输出结果的首地址
280     mov bx , si            ; bx用来做最后的数据存入,所以也是为输出结果的首地址
281 
282     mov al , ds:[ si ]        ;从得到的第一个数据开始遍历
283     mov ah , 0            ;只要低位,高位归零
284 
285     push ax                ;结束符先入栈
286 
287     ;把得出的字符倒过来,因为求余得到的数是倒着的
288 again_4:inc si
289 
290     mov al , ds:[ si ]
291     mov ah , 0            ;只要低位,高位归零
292 
293     mov cx , ax
294 
295     jcxz ok2            ;已经全部临时存入栈中
296 
297     push ax
298 
299     inc cx                ;因为loop会将cx减少1,所以要先加1
300 
301     loop again_4
302 
303   ok2:  pop cx                ;从栈中取出,正好实现倒叙
304 
305     mov ds:[ bx ] , cl        ;只要低位,高位归零
306 
307     jcxz return
308 
309     inc bx
310     inc cx                ;因为loop会将cx减少1,所以要先加1
311 
312     loop ok2
313 
314 return: pop bx                ; 恢复现场
315     pop cx                ; 恢复现场
316     ret                ; 返回
317 
318 
319 
320 
321 ;子程序
322 ;功能:在指定的位置 , 用指定的颜色 , 显示一个用0结束的字符串
323 ;参数:(dh) = 行号(取值范围0~24) , (dl) = 列号(取值范围0~79)
324 ;     (cl) = 颜色 , ds:si指向字符串首地址
325 show_str:
326 
327     push dx                ; 现场保护
328 
329     mov ax , 000ah            ;转换成行需要乘以a(10)
330     mul dh                ;计算写入位置的行
331     add ax , 0b800h            ;B800是起始位置,所以加上规定的行数
332 
333 
334     add dl , dl            ;计算写入位置的列
335     mov dh , 0
336 
337 
338     mov es , ax            ;设置写入位置的寄存器
339     mov di , dx
340     
341     mov al , cl            ;保存颜色
342 
343 
344     mov cx , 2
345     jmp first_start
346    again_2:
347 
348     mov cl , ds:[si]        ;获取要显示的数据
349     mov ch , 0            ;不需要高位
350     jcxz ok                ;如果是0则返回(结束这个子程序)
351     
352     mov es:[di] , cl        ;将字符写入
353     mov es:[di + 1] , al        ;写入颜色
354     add di , 2            ;指向下一个要写入的位置
355     inc si                ;指向下一个要读取字符的位置
356     mov cl , 2            ;again循环每次都成立
357 first_start:
358    loop again_2
359 ok:    pop dx                ; 恢复
360     ret                ;返回(结束)这个子程序
361 
362 
363 code ends
364 
365 
366 end start
原文地址:https://www.cnblogs.com/Zblogs/p/3285753.html