汇编语言-实验14--201202版

这篇是自己去年学习时候写的,重新放出来,可以和现在的对比一下:

实验要求:
编程:以“年/月/日  时:分:秒”的格式显示出当前的日期、时间。
准备工作:因为CMOS9号单元存储的是年份数据,那么该数据对应的是两位的十进制数字,拿今年2011年来说,9号单元里存储的就应该是BCD码:00010001.为了验证一下,同时也巩固下CMOS的读写操作,做了一个小程序,如下:
-----------------------------------
assume cs:code
code segment
start:
  mov al,9
  out 70h,al
  in al,71h
  mov bl,al

  mov al,8
  out 70h,al
  in al,71h
  mov bh,al

  mov ax,4c00h
  int 21h
code ends
end start
-----------------------------------
debug跟踪如下:

发现:
(1)因为一个内存单元表示为BCD码的话只能表示两位的十进制数,而年份为4位,做这个程序的初衷就是检验年份数据是否为后两位,可以看到最终bl=11h,即按BCD码来理解的话就是为11(十进制);没有问题。
(2)单步跟踪out 70h,...指令时,会继续执行下一句后再响应单步中断。至于是out指令,还是单独仅针对out 70h,..指令才会出现这一情况,我暂时也不愿意去深究了,至少明白了前几章说的不仅仅是mov ss,。。。指令才会暂不响应单步中断。

*分析:
在屏幕显示字符串,首先想到21h号中断的9号子程序;那么剩下的工作就是确定字符串的内容和地址了:1、内容的确定,可通过读取CMOS时间数据获得;2、地址的确定,可预设在数据段中。
以上是大致的框架,具体的流程如下:
(1)获取时间信息,存入指定数据段中;
(2)将上述时间信息写入预设字符串中;完成最终输出的字符串;
(3)调用10h号中断2号子程序,设置光标位置,即字符串在屏幕上的输出位置;
(4)调用21h号中断9号子程序,输出字符串。
编程细节分析如下:
(1)数据段的设置:需要两个指定区域分别存放已转为数字字符的时间数据和预设的显示字符串;同时在获取cmos时间信息过程中,因为需要对其不同内存单元进行读取,所以可采用实验13(3)中的方法,将各时间单元地址单独存于指定数据段,这样就方便采用循环的方式将其写入指定数据区;因此数据段的设置包括三部分内容:a、CMOS各时间信息的地址;b、存放已转为数字字符的时间数据区;c、预设(及最终)的显示字符串。
(2)在完成最终显示的字符串的过程中,可以观察到这个字符串并不规整,总共17个字符,但只需要对其中部分进行修改,而且这部分需要修改的单元的偏移地址也不是规则的递增;这样就需要换个思路了,这里需要修改的是时间信息对应的位,在修改字符串程序的过程中只需要判断当前位是否为时间信息位就可以了,那么在预设的字符串里先将时间信息位设置为0或者其他不为'/'or  '(space) or ':'就可以了。循环过程里直接判断当前位是否为0,为0则修改。

*代码:
assume cs:codesg,ds:data
data segment
  d1 db 9,8,7,4,2,0
  d2 db 12 dup (0)
  d3 db '00/00/00 00:00:00','$'
data ends
codesg segment
start:
  mov ax,data
  mov ds,ax
  mov bp,offset d1
  mov si,offset d2
  mov di,offset d3

;依次读取时间数据写入d2段
  mov cx,6
s:
  mov al,ds:[bp]
  out 70h,al
  in al,71h
  mov bl,al   ;暂存al
  push cx     ;保护循环次数
  mov cl,4
  shr al,cl   ;得到十位
  add al,30h
  and bl,00001111B   ;得到个位
  add bl,30h
  mov ds:[si],al
  inc si
  mov ds:[si],bl
  inc bp
  inc si
  pop cx
  loop s

;将d2段数据写入d3段,当d3段对应字符为'0'时候写入
  mov si,offset d2    ;重置
  mov cx,17           ;d3段长度为循环次数
s1:
  mov al,ds:[di]
  cmp al,30h
  jnz next
  mov al,ds:[si]
  mov ds:[di],al
  inc si
next:
  inc di
  loop s1

;调用10h中断置光标位置
  mov ah,2
  mov bh,0
  mov dh,10
  mov dl,20
  int 10h

;调用21h中断显示字符串
  mov dx,offset d3
  mov ah,9
  int 21h

  mov ax,4c00h
  int 21h

codesg ends
end start


*注意点:
在设置数据段data各数据区时候“标号”后面加了冒号(:),发现无法编译通过,提示missing or unreachable CS.在群里求助的时候大致知道了原因:就在于不该用冒号。这涉及到汇编里标号和变量的区别,暂时我也无法弄清楚,毕竟才学到这里。只需要知道:在数据段里设置的标号(其实也许应该称为变量)是不需要加":”的,而是用一个空格位。而在代码区里的标号则需要用冒号。

原文地址:https://www.cnblogs.com/tsembrace/p/3267183.html