《汇编语言》课程设计2

2019-07-30 19:15:49 浏览数 (1)

代码语言:javascript复制
  1 assume cs:code,ss:stack
  2 stack segment
  3     db 128 dup (0)
  4 stack ends
  5 code segment
  6 start:
  7     mov ax,stack
  8     mov ss,ax
  9     mov sp,128
 10     
 11     call copy_boot
 12     
 13     ;设置CS:IP为0:7e00h
 14     mov ax,0
 15     push ax
 16     mov ax,7e00h
 17     push ax
 18     retf
 19     
 20     mov ax,4c00h
 21     int 21h
 22 ;org 7e00h
 23 ;引导程序
 24 boot:
 25     jmp boot_begin
 26     func0    db 'Hk_Mayfly----XIUXIUXIU~',0
 27     func1    db '1) reset pc',0
 28     func2    db '2) start system',0
 29     func3    db '3) clock',0
 30     func4    db '4) set clock',0
 31     ;相减得到的是标号的相对位置, 7e00h得到的绝对位置
 32     func_pos    dw offset func0-offset boot 7e00h
 33                 dw offset func1-offset boot 7e00h
 34                 dw offset func2-offset boot 7e00h
 35                 dw offset func3-offset boot 7e00h
 36                 dw offset func4-offset boot 7e00h
 37     time    db 'YY/MM/DD hh:mm:ss',0
 38     cmos    db 9,8,7,4,2,0
 39     clock1    db 'F1----change the color        ESC----return menu',0
 40     clock2    db 'Please input Date and Time,(YY MM DD hh mm ss):',0
 41     change    db 12 dup (0),0
 42 
 43 boot_begin:
 44     call init_boot
 45     call cls_screen
 46     call show_menu 
 47     jmp choose
 48     mov ax,4c00h
 49     int 21h
 50 
 51 choose:
 52     call clear_kb_buffer
 53     ;获取我们输入的操作,跳转到对于函数
 54     mov ah,0
 55     int 16h
 56     cmp al,'1'
 57     je choose_func1
 58     cmp al,'2'
 59     je choose_func2
 60     cmp al,'3'
 61     je choose_func3
 62     cmp al,'4'
 63     je choose_func4
 64     
 65     jmp choose
 66 
 67 ;在题中提到了,开机后进入到ffff:0处执行指令
 68 ;那我们也可以把重启理解为,跳转到ffff:0执行指令
 69 ;所以我们利用jmp dword跳转到ffff:0地址,模拟重启
 70 choose_func1:
 71     mov bx,0ffffh
 72     push bx
 73     mov bx,0
 74     push bx
 75     retf
 76     
 77     jmp choose
 78 
 79 ;题中对引导现有的操作系统的描述是调用int 19,这里为了方便就直接写成函数了
 80 choose_func2:
 81     mov bx,0
 82     mov es,bx
 83     mov bx,7c00h
 84     
 85     mov al,1;扇区数
 86     mov ch,0
 87     mov cl,1;扇区
 88     mov dl,0
 89     mov dh,0
 90     mov ah,2;读取
 91     int 13h
 92     
 93     mov bx,0
 94     push bx
 95     mov bx,7c00h
 96     push bx
 97     retf
 98     
 99     jmp choose
100 
101 ;获取时间
102 choose_func3:
103     call show_time
104     
105     jmp choose
106 
107 show_time:
108     call init_boot
109     call cls_screen
110     ;显示按键信息
111     mov si,offset clock1-offset boot 7e00h
112     mov di,160*14 10*2;在14行10列显示
113     call show_line
114 show_time_start:
115     ;获取时间信息,并显示(将time中的未知字符替换为当前时间)
116     call get_time_info
117     mov di,160*10 30*2;屏幕显示的偏移地址
118     mov si,offset time-offset boot 7e00h;time标号的偏移地址
119     call show_line
120     
121     ;获取键盘缓存区的数据
122     mov ah,1
123     int 16h
124     ;没有数据就跳回show_time_start
125     jz show_time_start
126     ;判断是否按下F1
127     cmp ah,3bh
128     je change_color
129     ;判断是否按下ESC
130     cmp ah,1
131     je Return_Main
132     ;有数据,但是是无用的键盘中断,清除
133     cmp al,0
134     jne clear_kb_buffer2
135     ;返回开始,重复之前的操作,达到刷新时间的效果。
136     jmp show_time_start
137 
138 change_color:
139     call change_color_show
140 clear_kb_buffer2:
141     call clear_kb_buffer
142     jmp show_time_start
143 Return_Main:
144     ;返回到开始,重新打印菜单
145     jmp boot_begin
146     ret
147 
148 choose_func4:
149     call set_time
150     jmp boot_begin
151     
152 set_time:
153     call init_boot
154     call cls_screen
155     call clear_stack
156     
157     ;设置提示信息显示位置
158     mov di,160*10 13*2
159     mov si,offset clock2-offset boot 7e00h
160     call show_line
161     ;显示修改后change中的内容
162     mov di,160*12 26*2
163     mov si,offset change-offset boot 7e00h
164     call show_line
165     
166     call get_string
167 
168 get_string:
169     mov si,offset change - offset boot   07e00H
170     mov bx,0
171 getstring:
172     ;获取键盘输入的时间信息
173     mov ah,0
174     int 16h
175     
176     ;输入的时间为数字0~9
177     cmp al,'0'
178     jb error_input
179     cmp al,'9'
180     ja error_input
181     ;将我们输入的时间字符入栈
182     call char_push
183     ;不能超过输入的数量
184     cmp bx,12
185     ja press_ENTER
186     mov di,160*12 26*2
187     call show_line
188     jmp getstring
189 error_input:
190     ;判断是不是按下退格或回车键
191     cmp ah,0eh
192     je press_BS
193     cmp ah,1ch
194     je press_ENTER
195 
196     jmp getstring
197 ;按下回车
198 press_BS:
199     call char_pop
200     mov di,160*12 26*2
201     call show_line
202     jmp getstring
203 ;按下enter就退出
204 press_ENTER:
205     ret
206 
207 char_push:
208     ;只能最多输入12个梳子
209     cmp bx,12
210     ja char_push_end
211     ;将数值移动到对应位置
212     mov ds:[si bx],al
213     inc bx;表示我们输入了多少个字符
214 char_push_end:
215     ret
216 
217 char_pop:
218     ;判断是否输入了设置时间的数值,没有就相当于删完了
219     cmp bx,0
220     je char_pop_end
221     ;否则用星号替换,相当于删除
222     dec bx
223     mov byte ptr ds:[si bx],'*'
224 char_pop_end:
225     ret
226 
227 clear_stack:
228     push bx
229     push cx
230     
231     mov bx,offset change-offset boot 7e00h
232     mov cx,12
233 cls_stack:
234     ;替换change段中内容
235     mov byte ptr ds:[bx],'*'
236     inc bx
237     loop cls_stack
238     
239     pop cx
240     pop bx
241     ret
242     
243 
244 ;获取时间
245 get_time_info:
246     ;从cmos ram获取年月日,时分秒6个数据
247     mov cx,6
248     ;获取存放单元地址
249     mov bx,offset cmos - offset boot   7e00H
250     ;通过替换来显示
251     mov si,offset time - offset boot   7e00H
252 next_point:   
253     push cx
254     ;获取单元号
255     mov al,ds:[bx]
256     ;向70h端口写入要访问的单元地址,并从71h端口读取数据
257     out 70H,al
258     in al,71H
259     ;右移4位获取十位
260     mov ah,al
261     mov cl,4
262     shr al,cl
263     and ah,00001111b
264     ;将BCD码转换为ASCII码
265     add ax,3030H
266      ;写入time中
267     mov word ptr ds:[si],ax
268     ;下一单元号
269     inc bx
270     ;每个数据之间距离都是3
271     add si,3
272     pop cx
273     loop next_point
274     ret
275 
276 ;改变颜色
277 change_color_show:
278     push bx
279     push cx
280  
281     mov cx,2000
282     mov bx,1
283 next:
284     ;属性值 1,改变颜色
285     add byte ptr es:[bx],1
286     ;当超出字体颜色的数值(0~111h)时,将数值重置
287     cmp byte ptr es:[bx],00001000b
288     jne change_end
289     ;因为背景是黑色,所以文字颜色就不设置成黑色了
290     mov byte ptr es:[bx],1
291 change_end:
292     add bx,2
293     loop next
294  
295     pop cx
296     pop bx
297     ret
298 
299 clear_kb_buffer:
300     ;1号程序,用来检测键盘缓冲区是否有数据
301     ;如果有的话ZF!=0,没有,ZF=0
302     mov ah,1
303     int 16h
304     ;通过ZF判断减缓缓冲区是否有数据,没有就跳出
305     jz clear_kb_bf_end
306     mov ah,0
307     int 16h
308     jmp clear_kb_buffer
309 clear_kb_bf_end:
310     ret
311 
312 init_boot:
313     ;基本设置,注意:程序的直接定址表默认段地址是CS
314     ;当程序转移到7c00h时,代码中CS值未发生改变,
315     ;所以需要我们指明段地址
316     mov bx,0b800h
317     mov es,bx
318     mov bx,0
319     mov ds,bx
320     ret
321     
322 ;清屏
323 cls_screen:
324     mov bx,0
325     mov cx,2000
326     mov dl,' '
327     mov dh,2;字体为绿色,不设置的话,在我们显示菜单时,字体和背景颜色相同
328 s:    mov es:[bx],dx
329     add bx,2
330     loop s
331 sret:
332     ret
333 
334 ;展示界面
335 show_menu:
336     ;在10行,30列显示菜单
337     mov di,160*10 30*2
338     ;保存在直接定址表的绝对位置
339     mov bx,offset func_pos-offset boot 7e00h
340     ;菜单有5行
341     mov cx,5
342 s1:
343     ;这里相当于外循环,每次一行
344     ;获取func_pos中每行的保存位置的偏移地址
345     mov si,ds:[bx]
346     ;调用内循环函数,输出一行的每个字符
347     call show_line
348     ;下一行偏移地址
349     add bx,2
350     ;下一行显示
351     add di,160
352     loop s1
353     ret
354     
355 show_line:
356     push ax
357     push di
358     push si
359 show_line_start:
360     ;获取这一行的第si 1个字符
361     mov al,ds:[si]
362     ;判断是否到末尾
363     cmp al,0
364     je show_line_end
365     ;保存字符到显示缓冲区
366     mov es:[di],al
367     add di,2
368     inc si
369     jmp show_line_start
370 show_line_end:
371     pop si
372     pop di
373     pop ax
374     ret
375 
376 boot_end:nop
377 
378 ;转存引导程序
379 copy_boot:
380     ;将引导程序储存到指定位置
381     mov ax,0
382     mov es,ax
383     mov di,7e00h
384     
385     mov ax,cs
386     mov ds,ax
387     mov si,offset boot
388     mov cx,offset boot_end-offset boot
389     cld
390     rep movsb
391     
392     ret
393 
394 code ends
395 end start

具体的在注释中都说明了。

jz指令:https://zhidao.baidu.com/question/564008138.html

int 16的1号程序:https://zhidao.baidu.com/question/511189643.html

总结

  汇编的难度并不大,我认为在有编程的基础上,学习汇编要做到细致,细致的理解计算机编程的编译过程,对于我理解其他编程语言也有很大的帮助。欢迎大家关注,一起交流。

0 人点赞