說的多不如做的多,子程序的功能十分重要,這篇筆記用來記錄書上練習題的代碼,加強對子程序的應用。
在屏幕上指定位置顯示字符串
在轉移指令那一章有個聯繫是要求在屏幕中間顯示不同顏色的字體,當時我寫的代碼是這樣
1 assume cs:codesg,ds:data 2 3 data segment 4 db 'welcome to masm!' 5 data ends 6 7 codesg segment 8 9 start: mov ax,data 10 mov ds,ax 11 mov bx,0 12 mov ax,0B800h 13 mov es,ax 14 15 ;第10行中間顯示綠色字體 16 mov si,10*160+32 17 mov cx,16 18 s: mov al,ds:[bx] 19 mov es:[si+24],al 20 mov byte ptr es:[si+25],02h 21 inc bx 22 inc si 23 inc si 24 loop s 25 26 ;第11行中間顯示紅底綠色字體 27 mov si,11*160+32 28 mov bx,0 29 mov cx,16 30 s1: mov al,ds:[bx] 31 mov es:[si+24],al 32 mov byte ptr es:[si+25],42h 33 inc bx 34 inc si 35 inc si 36 loop s1 37 38 ;第12行中間顯示白底藍色字體 39 mov si,12*160+32 40 mov bx,0 41 mov cx,16 42 s2: mov al,ds:[bx] 43 mov es:[si+24],al 44 mov byte ptr es:[si+25],71h 45 inc bx 46 inc si 47 inc si 48 loop s2 49 50 mov ax,4c00h 51 int 21h 52 53 codesg ends 54 end start
在學習了子程序之後可以更簡潔的代碼實現該功能
1 assume cs:codesg,ds:data 2 3 4 data segment 5 db 'welcome to masm!',0 6 data ends 7 8 codesg segment 9 10 start: mov ax,data 11 mov ds,ax 12 mov ax,0B800h 13 mov es,ax 14 ;第10行中間顯示綠色字體 15 mov dh,10D 16 mov dl,32D 17 mov bl,02h 18 call print 19 ;第11行中間顯示紅底綠色字體 20 mov dh,11D 21 mov dl,32D 22 mov bl,42h 23 call print 24 ;第12行中間顯示白底藍色字體 25 mov dh,12D 26 mov dl,32D 27 mov bl,71h 28 call print 29 30 mov ax,4c00h 31 int 21h 32 33 print: push ax 34 push dx 35 push bx 36 mov al,160D 37 mul dh 38 mov cl,dl 39 mov ch,0 40 add ax,cx ;得到開始寫入字符串的內存地址 41 mov si,ax 42 mov di,0 43 s: mov cl,ds:[di] 44 mov ch,0 45 jcxz s1 46 mov es:[si],cl 47 mov byte ptr es:[si+1],bl 48 inc di 49 inc si 50 inc si 51 loop s 52 s1: pop bx 53 pop ax 54 pop dx 55 ret 56 57 codesg ends 58 end start
數值轉換
1 assume cs:codesg,ds:data 2 3 4 data segment 5 db 10 dup(0) 6 data ends 7 8 codesg segment 9 10 start: mov ax,data 11 mov ds,ax 12 mov si,0 13 mov ax,1266d 14 call doc 15 16 ;第10行中間顯示綠色字體 17 mov dh,10D 18 mov dl,32D 19 mov bl,02h 20 call print 21 22 23 mov ax,4c00h 24 int 21h 25 26 doc: push ax 27 push si 28 s0: mov bl,10d 29 div bl 30 add ah,30h 31 mov ds:[si],ah 32 mov ah,0 33 inc si 34 mov cl,al 35 mov ch,0 36 jcxz s2 37 jmp short s0 38 39 s2: mov byte ptr ds:[si],0 40 pop si 41 pop ax 42 ret 43 44 45 print: push ax 46 push dx 47 push bx 48 mov ax,0B800h 49 mov es,ax 50 mov al,160D 51 mul dh 52 mov cl,dl 53 mov ch,0 54 add ax,cx ;得到開始寫入字符串的內存地址 55 mov si,ax 56 mov di,0 57 s: mov cl,ds:[di] 58 mov ch,0 59 jcxz s1 60 mov es:[si],cl 61 mov byte ptr es:[si+1],bl 62 inc di 63 inc si 64 inc si 65 loop s 66 s1: pop bx 67 pop ax 68 pop dx 69 ret 70 71 codesg ends 72 end start
課程設計1
1 assume cs:codesg,es:data,ss:stack 2 data segment 3 ;年份 4 db '1975','1976','1977','1978','1979','1980','1981','1982','1983' 5 db '1984','1985','1986','1987','1988','1989','1900','1991','1992' 6 db '1993','1994','1995' 7 ;公司總收入 8 dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514 9 dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000 10 ;僱員 11 dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226 12 dw 11542,14430,45257,17800 13 data ends 14 15 ;棧空間 16 stack segment 17 db 16 dup(0) 18 stack ends 19 20 ;臨時內存空間,將字符串後面加0 21 temp segment 22 db 8 dup(0) 23 temp ends 24 25 codesg segment 26 27 start: ;清除屏幕上的原有內容 28 mov ax,0b800h 29 mov es,ax 30 mov si,0 31 mov cx,25*80 32 x: mov byte ptr es:[si],' ' 33 mov byte ptr es:[si+1],0 34 inc si 35 inc si 36 loop x 37 ;分配棧空間 38 mov ax,stack 39 mov ss,ax 40 mov sp,16 41 ;指定數據入口 42 mov ax,data 43 mov es,ax 44 mov ax,temp 45 mov ds,ax 46 mov si,0 47 mov di,0 48 mov bx,0 49 mov dh,4 50 ;循環21次,輸出21年數據 51 mov cx,21 52 53 x1: push cx 54 ;顯示年份 55 mov ax,es:[di] 56 mov ds:[si],ax 57 mov ax,es:[di+2] 58 mov ds:[si+2],ax 59 mov byte ptr ds:[si+4],0 60 mov dl,10 61 mov cl,02h 62 call print 63 64 ;顯示公司收入 65 mov ax,es:[di+84] 66 push dx 67 mov dx,es:[di+84+2] 68 call dword_str 69 pop dx 70 mov dl,20h 71 call print 72 73 ;顯示僱員人數 74 mov ax,es:[bx+84+84] 75 call word_str 76 mov dl,40h 77 call print 78 79 ;計算人均收入並顯示 80 mov ax,es:[di+84] 81 push dx 82 mov dx,es:[di+84+2] 83 div word ptr es:[bx+84+84] 84 call word_str 85 pop dx 86 mov dl,60h 87 call print 88 add di,4 89 add bx,2 90 inc dh 91 pop cx 92 loop x1 93 94 mov ax,4c00h 95 int 21h 96 97 98 99 100 ;顯示ds:[si]開始的字符串 101 print: push es 102 push ax 103 push dx 104 push bx 105 push si 106 push di 107 push cx 108 109 mov ax,0B800h 110 mov es,ax 111 mov al,160D 112 mul dh 113 mov bl,dl 114 mov bh,0 115 add ax,bx ;得到開始寫入字符串的內存地址 116 mov di,ax 117 mov si,0 118 mov ah,cl 119 print_s: mov cl,ds:[si] 120 mov ch,0 121 jcxz print_s1 122 mov es:[di],cl 123 mov byte ptr es:[di+1],ah 124 inc si 125 inc di 126 inc di 127 loop print_s 128 print_s1: pop cx 129 pop di 130 pop si 131 pop bx 132 pop dx 133 pop ax 134 pop es 135 ret 136 137 ;不會溢出的除法,參考公式X/N = int(H/N)*65536 + [rem(H/N)*65536 + L]/N 138 ;65536=2^16=10000h 139 ;(dx)被除數高16位 (ax)被除數低16位,(cx)除數 140 ;返回(dx)商高16位 (ax)商低16位 (cx)餘數 141 divdw: push bx 142 push ax ;將被除數低16位入棧 143 mov ax,dx 144 mov dx,0 145 div cx ;處理被除數的高16位,商放在ax中,餘數放在dx中 146 mov bx,ax;bx存儲高16位的商,作爲最終結果的高16位int(H/N)*65536 147 pop ax ;低16位出棧,這是(dx)=被除數高16位的餘數即上面公式的rem(H/N)*65536 148 div cx ;處理低16位,[rem(H/N)*65536 + L]/N,餘數放在dx中 149 mov cx,dx 150 mov dx,bx 151 pop bx 152 ret 153 154 ;dword型數據轉化爲字符串,ds:[si] 155 ;(dx)高16位,(ax)低16位 156 dword_str: push bx 157 push cx 158 push dx 159 push ax 160 push si 161 mov bx,0 162 163 dword_str_x:mov cx,10;cx存儲除數 164 call divdw 165 push cx;將餘數入棧,若不用棧操作則顯示時是相反的順序 166 inc bx 167 mov cx,dx 168 jcxz dword_str_a;如果商的高16位等於0則驗證低16位是否等於0 169 jmp near ptr dword_str_x 170 dword_str_a:mov cx,ax 171 jcxz dword_str_x1;如果商的低16位也等於0則退出循環 172 jmp near ptr dword_str_x 173 174 175 dword_str_x1:mov cx,bx;循環次數 176 dword_str_x2:pop ds:[si] 177 add byte ptr ds:[si],30h;將數字+30h變成相應的字符串 178 inc si 179 loop dword_str_x2 180 181 pop si 182 pop ax 183 pop dx 184 pop cx 185 pop bx 186 ret 187 188 ;word型數據轉化爲字符串 189 word_str: push bx 190 push cx 191 push dx 192 push ax 193 push si 194 mov bx,0 195 word_str_s: mov dx,0;防止溢出用16位除法 196 mov cx,10 197 div cx 198 push dx 199 inc bx 200 mov cx,ax 201 jcxz word_str_x 202 jmp short word_str_s 203 204 word_str_x: mov cx,bx 205 word_str_x1:pop ds:[si] 206 add byte ptr ds:[si],30h;將數字+30h變成相應的字符串 207 inc si 208 loop word_str_x1 209 210 pop si 211 pop ax 212 pop dx 213 pop cx 214 pop bx 215 ret 216 217 218 codesg ends 219 220 end start