| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 10086 人关注过本帖
标题:大家来写写汇编小玩意(三)
只看楼主 加入收藏
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
回复 20楼 wmf2014
这个我也实作过了,但有限制的,好像是1970-2xxx,这个xxx记不起是什么,
但不会是999这么大,我改用计算就是不爽这个限制,基本上计算并无限制,
公元到几万年都没问题。

另有一点, int 2ah/2ch这些日期函数,在dosbox或模拟器或freedos等系统不一定有作用,结果是让人气结,不如直接计算。
2016-06-30 17:36
八画小子
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:贵宾
威 望:37
帖 子:709
专家分:2063
注 册:2010-11-11
收藏
得分:0 
回复 21楼 Valenciax
你写好程序,放在bochs上用啊。基本你用到的BIOS调用,它都有。
2016-07-01 15:25
wmf2014
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:216
帖 子:2039
专家分:11273
注 册:2014-12-6
收藏
得分:0 
回复 21楼 Valenciax
在winxp里调整时间试了下,年份到2099年就回到1980了,不知道在int21h里会这样不。非要计算的话,用下面的代码即可,已验证:
程序代码:
redate:    ;本函数返回指定年、月份的天数,输入参数cx:年 dh:月,按int21h的2ah习惯给参数,天数从ax中返回
    push bx
    push dx
    push si
    push di
    xor ax,ax
    mov al,dh
    mov di,ax
    mov bx,30
    cmp di,2
    jnz relp1              ;不是2月,按普通月份处理
    mov bx,28              ;如是2月,则做闰年判断
    xor dx,dx
    mov ax,cx
    mov si,400
    div si
    or dx,dx
    jz relp2               ;能被400整除,是闰年
    xor dx,dx
    mov ax,cx
    mov si,4
    div si
    or dx,dx
    jnz relp1              ;不是闰年,按普通月份处理
    mov ax,cx
    mov si,100
    div si
    or dx,dx
    jnz relp2              ;不能被100整除,是闰年
relp1:    cmp di,8
    jb relp3
relp2:    inc di                 ;闰年和大于7月份的月份处理
relp3:    and di,1
    mov ax,di
    add ax,bx
    pop di
    pop si
    pop dx
    pop bx
    ret

能编个毛线衣吗?
2016-07-01 20:49
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
回复 22楼 八画小子
能不能调用是次要,主要是BIOS/DOS有年份的设定限制,任何高阶语言甚至EXCEL的日期函数都是这个限制,倒不如自己计算。

[此贴子已经被作者于2016-7-2 16:53编辑过]

2016-07-02 07:16
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:340
专家分:2482
注 册:2016-5-15
收藏
得分:0 
题二代码:

下面的版本和1楼写的不一样,为了代码的重用,主要几个功能都封装成子程式,
利用参数传递就能使用。
也因为要封装,所以用了invoke和local区域变量,须用masm6.x以后版本编译
编译方法:  ml  xxxx.asm

几个有点用的子程序,可以在其他程式使用
1.
invoke GetmonthDay, month
输入月份得出该月份最大天数,month可以是暂存器,变量或立即数,可混用。
比如:
invoke GetmonthDay,ax    ;ax=输入月份,传回该月最大天数
invoke GetmonthDay,12    ;输入月份=12(立即数),传回12月最大天数=31

2.
GetTotalDay year,month,day
输入年月日,得出该日期和1000/1/1相差的总天数由dx:ax传回
year,month和day可以是暂存器,变量或立即数,可混用
比如:
invoke GetTotalDay,ax,bx.cx ;ax=年,bx=月,cx=日
invoke GetmonthDay,2016,12,29   ;传回该日期1000/1/1相差天数,由dx:ax传回

大家或者有疑问,这子程序只有这条题目才适用吧,比如只想计算某年某月某日的总天数,岂不得物无所用?
换一个想法,把该年该月该日当参数求得A值,该年1月1日作参数求得B值,A-B+1,就是该年该月该日的总天数了。
虽然是绕了一个圈子,但高阶语言/WINDOW API等,呼叫一个函数难道绕的圈子少了,这是封装程序无可避免的代价。

3.
invoke GetDate,address
address缓冲地址,传回ax=年,bx= 月,cx=日,dx= 0 (非闰年), =1(闰年)
用法:
先在资料区定义一个缓冲 
InputBuffer db 11,0,11 dup (0)
...
...
lea mov si,InputBuffer
invoke GetDate,si
若使用者若输入31/11/2016
则ax=2016,bx=11,cx=31,dx=1(闰年)
若使用者输入29/2/2015或31/11/2018等错误日期,则传回cf=1

4.
LeapYear子程序
使用方法
mov ax,年份
call LeapYear ;传回AX=1(闰年),AX=0(非闰年)

程序代码:
;程式功能:输入两个日期,计算两个日期相差天数
;因用了invoke和local区域变量,须用masm6.x以后版本编译
;编译方法:  ml  xxxx.asm
;
.MODEL  small,stdcall
.data

 InputBuffer db 11,0,11 dup (0)  

 FirstStr db 10,13,'Input First Date(dd/mm/yyyy):','$'

 SecondStr db 10,13,'Input Second Date(dd/mm/yyyy):','$'

 DayDiffStr db 10,13,'Difference:'

 DayDiffNum db 10 dup (20h)

 DaysStr db ' day(s)$'

 DaysStr_len equ $ - offset DaysStr

 UserTotaldate dd 0,0

 InputCount dw 0
.stack 100h
.code
;---------------------------------------------------------------------
; ------ 主程式在后段,请由start: 开始阅读------------------
;---------------------------------------------------------------------
;输入月份,传回ax=该月天数,若输入不符(1-12之外),cf=1
GetmonthDay proc near GiveMonth:word     ;(1-12)
     push bx
     mov bx,GiveMonth
     dec bx
     cmp bx,11
     ja GetMdxErr
     mov ax,28
     cmp  bx,1  ;是否2月
     jz GetMDok ;
     cmp bx,6   ;少于等于7月
     jbe GetMD10
     inc bx  ;大于7月加1
GetMD10:mov ax,30
     test bx,1
     jnz GetMDok  ;奇数不加ax=30
     inc ax ;偶数加1,ax=31
GetMDok:clc  ;ax=月份天数
     jmp short GetMDxErrx
GetMDxErr:
     stc
GetMDxErrx:     
     pop bx
     ret
GetmonthDay  endp 
;-------------------------------------------------------------------
GetTotalDay proc near xyear:word,xmonth:word,xday:word
  local TotalHi,TotalLo,LLyear:word ;区域变量(32bit总天数),闰月调整(0或1)

     xor ax,ax
     mov word ptr TotalLo,ax     ;初始化
     mov word ptr TotalHi,ax ;初始化
     mov word ptr LLyear,ax ;初始化
     mov ax,xyear ;取年份
     call LeapYear  ;输入AX=年份,输出AX=1(闰年),AX=0(非闰年)         
     or ax,ax
     jz  GetTDA
     mov word ptr LLyear,1
GetTDA:mov di,xyear ;取年份

GetTD0:cmp di,1000 ;和基准1000比较
     ja GetTD3 ;大于
     jz GetTD4 ;等于,则不处理输入年份和1000的相差
     ; di = less then 1000  
     mov si,+1 ;预设加
     mov ax,di ;取得输入年份
GetTD1:call LeapYear ;是否闰年
     mov bx,365 ;一年多少天
     or ax,ax  ;是否闰年?
     jz  GetTD2 ;不是
     inc bx  ;是闰年,365+1
GetTD2:
     add word ptr TotalLo,bx ;加总日期
     adc word ptr TotalHi,0 ;带进位加
     add di,si    ;输入年份 加或减1 , 用以接近1000
     jmp short GetTD0
GetTD3:     ;大于1000到此
     lea ax,[di-1] ;本年不计,取前一年值,若di=2017,lea ax,[di-1]后, ax=2016
     mov si,-1; ;预设减,, 用以接近1000
     jmp short GetTD1 ;回去计算闰年
GetTD4:      ;得该年和1000/1/1相差年日数
     ;取得第一输入年月日,且已计算 和1000/1/1相差年日数
     mov dx,1  ;以下计算该年总天数
     xor ax,ax
     xor si,si
     mov dx,1  ;由1月起
     cmp xmonth,dx ;输入月份是否1月
     jz GetTD7 ;
GetTD5:cmp dx,xmonth 
     jae GetTD7
     invoke GetmonthDay, dx  ;以月份(dx)查找该月天数
     cmp dx,2 ;是否2月
     jnz GetTD6 ;不是
     add ax,LLyear ;若闰月调整 28->29
GetTD6:add si,ax ;累加
     inc dx ;下一月
     jmp short GetTD5
GetTD7:mov ax,si ;取加总
     add ax,xday ;加上输入天数
     ;得该年总天数
     add word ptr TotalLo,ax ;加总日期
     adc word ptr TotalHi,0 ;带进位加
     mov dx,TotalHi
     mov ax,TotalLo   ;总天数由dx:ax传回
     ret
GetTotalDay endp 
;--------------------------------------------------------------------------
;转值子程序,把输入的10进制文字转成16进制
;输入:ds:si数字字符串起点,以0dh结束
;输出:ax=转换后的16进制值,cf=1表示有非数字字符
GetValue:
     push bx
     push di
     xor bx,bx
     mov di,10
GetV10:lodsb     ;指向起点
     mov ah,0 ;清除
     ;cmp al,0 ;0dh ;回车?
     cmp al,0  ;-----zero
     jz Getvx
     cmp al,'0' ;以下比较0-9,否则cf=1离开
     jb Getvy
     cmp al,'9'
     ja Getvy
     sub al,'0'  ;ascii -> 值
     xchg bx,ax  ;交换
     mul di
     add bx,ax  ;累加
     jmp short GetV10
Getvx:
     mov ax,bx ;ascii转值后由ax转回
     clc ;成功cf=0
     jmp short Getvz
Getvy:
     stc  ;错误 cf=1
Getvz:
     pop di
     pop bx
     ret
;------------------------------------
;以下程序送出dx:ax的32bit结果到di,也可改成印出
;output DX:AX,dword (0-FFFFFFFFh / 0-4294967295)
print_dec:      xor cx,cx
     xchg bp,dx
     mov si,10 ;div by 10
     mov bx,30h
print_dec1: or bp,bp
     jz print_dec3
     xchg bp,ax
     xor dx,dx
     div si
     xchg bp,ax
     div si
     or dl,bl
     push dx
     inc cx
     jmp short print_dec1
print_dec3:  xor dx,dx
     div si
     or dl,bl
     push dx
     inc cx
     or ax,ax
     jnz print_dec3
print_dec4: pop ax
     stosb
     loop print_dec4
     ret
;--------------------------------------------------------------
GetDate proc near BufferAdd:word    

 local Uyear,Umonth,Uday,LimitDay,splitCount,LYear:word

 local UserInputAddress[4]:word

     mov word ptr splitCount,0  ; [/]数目初始化
     mov word ptr LYear,0  ;闰年初始化
     mov dx,BufferAdd
     mov di,dx
     mov ax,0C0Ah
     int 21h
     add di,2 ;指向字串符位置
     xor cx,cx
     mov cl,[di-1] ;取实际输入数
     mov bx,cx
     or cx,cx
     jnz  okinput
     mov ax,0    ;没有输入
     jmp short GetdataXX
GetdataX:
     mov ax,-1   ;错误输入
GetdataXX:
     stc
     ret
okinput:
     mov byte ptr [di+bx],0   ;0dH ->0
     mov al,'/'  ;分隔符
     lea bx,UserInputAddress
retry:
     repnz scasb 
     jnz NotFound
     mov ss:[bx],di
     mov byte ptr [di-1],0   ;清除分隔符
     inc splitCount ;加分隔符数目
     add bx,2 ;下一地址
     or cx,cx  ;完了?
     jnz retry ;
NotFound:
     cmp splitCount,2  ;只容许2个[/]分隔符
     jnz GetdataX  ;不符
     mov si, UserInputAddress[2] ;取年
     call GetValue ;取值
     cmp ax,4000 ;以下比较限制1000-4000
     ja GetdataX
     cmp ax,1000
     jb GetdataX
     mov Uyear,ax  ;
     mov si,UserInputAddress[0]  ;取月
     call GetValue  ;传回AX(月)
     mov Umonth,ax  ;
     invoke GetmonthDay,ax  ;取该月天数限制
     jc GetdataX   ;不符(1-12)
     mov LimitDay,ax  ;存天数限制
     mov si,BufferAdd
     add si,2  ;指向日期
     call GetValue ;取值
     mov Uday,ax  ;存输入日期 
     mov ax,Uyear  ;取输入年份
     Call LeapYear ;计算是否闰年子程序,传回1表示闰年,0表示非闰年
     or ax,ax ;是闰年不?
     jz GetTD  ;不是闰年
     mov word ptr LYear,1  ;闰年
     cmp Umonth,2  ;二月?
     jnz GetTD  ; 不是二月
     inc LimitDay ;闰年,2月份的限制+1
GetTD:
     mov ax,Uday  ;使用者输入日期
     cmp ax,LimitDay  ;比较输入日期和该月份天数限制
     ja GetdataX ;输入日期大于月份限制, 再输入 
     clc    ;所有日期输入正常
     mov ax,Uyear  ;传回年
     mov bx,Umonth ;传回月
     mov cx,Uday ;传回日
     mov dx,LYear ;闰年与否...0=不是,1=是
     ret
GetDate  endp 
;-------------------------------------------------------------------
LeapYear:  ;输入AX=年份,输出AX=1(闰年),AX=0(非闰年)
     push bx
     push dx
     push si
     mov si,ax
     mov bx,400 ;年份除以400余数等于零,为闰年
     mov dx,0
     div bx
     or dx,dx ;是否0 
     jz last ;余数为零,直接输出闰年 
     mov dx,0 
     mov bx,4 ;除以400余数不等于0,进行除以4余数是否等0的判断
     mov ax,si 
     div bx
     or dx,dx  ;是否0
     jz ok ;除以四余数等于0,跳往除以100余数是否等0的判断
over:    ;除以四余数不等于0,则不为闰年,结束 
     mov ax,0  ;不是闰年
     jmp nil
ok:
     mov bx,100 ;除以100余数为零,则不为闰年,余数不为零,则为闰年
     mov dx,0
     mov ax,si 
     div bx
     or dx,dx ;是否0
     jz over 
last:
     mov ax,1 ;闰年
nil:
     pop si
     pop dx
     pop bx
     ret
;----------------------------------------------------------------------------
;--------------------------主程式-----------------------------------------
;----------------------------------------------------------------------------
start:
     MOV AX,@DATA
     MOV DS,AX
     MOV ES,AX
     cld   ;正向
;-------------输入/测试开始------------------------------------------------
     mov inputCount,0  ;初始化
TryInput:
     cmp inputCount,0  ;根据inputCount决定显示第1/第2字符串
     lea dx,FirstStr     
     jz Whoinput
     lea dx,SecondStr    
Whoinput:
     mov ah,9
     int 21h
     lea si,InputBuffer  ;输入缓冲,要求输入格式(dd/mm/yyyy)
     invoke GetDate,si  ;读取输入子程序,传回ax(年),bx(月),cx(日),dx(闰年)
     jnc Nextin ;正常
     or ax,ax   ;没有输入
     jz quit  ;离开
     jmp short TryInput  ;输入错误
Nextin:
     invoke GetTotalDay,ax,bx,cx ;输入年,月,日....传回dx:ax=总天数 (由输入日期至1000/1/1)
     mov bx,inputCount
     shl bx,1              ; x 2
     shl bx,1              ; x 4
     mov word ptr UserTotaldate[bx],ax   ;根据inputCount存入总天数
     mov word ptr UserTotaldate[bx+2],dx
     inc inputCount  ;next input ?
     cmp inputCount,2  
     jb TryInput  ;second输入
;-------------输入/测试完成------------------------------------------------
    mov ax,word ptr UserTotaldate
    mov dx,word ptr UserTotaldate+2   ;取第1输入值入:dx:ax
    mov bx,word ptr UserTotaldate+4
    mov cx,word ptr UserTotaldate+6    ;取第2输入值入:cx:bx
    cmp dx,cx  ;比较高位
    ja noChg  ;大于
    jb xxchg  ;少于
      ;-- 32高位相等
    cmp ax,bx  ;比较低位
    jae noChg  ;大于等于不交换
xxchg:
     xchg ax,bx ;少于则交换
    xchg dx,cx
noChg:
     sub ax,bx
     sbb dx,cx
     mov di,offset DayDiffNum
     Call print_dec  ; 输出结果至字符串
     mov si,offset  DaysStr 
     mov cx,DaysStr_len
     rep movsb
     mov dx,offset DayDiffStr ;印结果
     mov ah,9
     int 21h
     mov ah,7 ;暂停
     int 21h
quit:
     mov ax,4c00h   ;离开
     int 21h
;--------------------------------------------------------------------------
end start


[此贴子已经被作者于2016-7-3 11:25编辑过]

2016-07-02 15:34
zhulei1978
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:53
帖 子:1351
专家分:1200
注 册:2006-12-17
收藏
得分:0 
这个跟bochs有什么关系,又不写操作系统

其实我就是改变社会风气,提高少女素质,刺激电影市道,提高年轻人内涵,玉树临风,风度翩翩的整蛊专家,我名叫古晶,英文名叫JingKoo!
2016-07-02 16:49
快速回复:大家来写写汇编小玩意(三)
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.124301 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved