Tvůrce webu je i pro tebe! Postav třeba web. Bez grafika. Bez kodéra. Hned.
wz

DOS_CLK.ASM

Obsluha hodin


; ============================================================================
;
;                          MicroDOS - DOS clock
;
; ============================================================================

; ----------------------------------------------------------------------------
;                           Pack 4 bytes to BCD
; ----------------------------------------------------------------------------
; INPUT:	DH,DL,AH,AL = binary numbers to pack
; OUTPUT:	DH,DL,AH,AL = BCD numbers
; ----------------------------------------------------------------------------

; ------------- Pack DX

BinBCDD:	xchg	ax,dx		; prepare words
		call	BinBCDW		; pack word in AX to BCD
		xchg	ax,dx		; return words

; ------------- Pack AH

BinBCDW:	xchg	al,ah		; prepare bytes
		call	BinBCDB		; pak byte in AL to BCD
		xchg	al,ah		; return bytes

; ------------- Push registers

BinBCDB:	push	cx		; push CX
		mov	cx,ax		; CH <- push registers AH

; ------------- Pack number in AL

		aam			; unpack digits
		mov	cl,4		; CL <- number of rotations
		shl	ah,cl		; shift AH 4 bits left
		or	al,ah		; AL <- BCD number

; ------------- Pop registers

		mov	ah,ch		; pop register AH
		pop	cx		; pop CX
		ret

; ----------------------------------------------------------------------------
;                             Unpack 4 BCD bytes
; ----------------------------------------------------------------------------
; INPUT:	DH,DL,AH,AL = BCD numbers to unpack
; OUTPUT:	DH,DL,AH,AL = binary numbers
; ----------------------------------------------------------------------------

; ------------- Unpack DX

BCDBinD:	xchg	ax,dx		; prepare words
		call	BCDBinW		; unpack BCD word in AX
		xchg	ax,dx		; return words

; ------------- Unpack AH

BCDBinW:	xchg	al,ah		; prepare bytes
		call	BCDBinB		; unpack BCD byte in AL
		xchg	al,ah		; return bytes

; ------------- Push registers

BCDBinB:	push	cx		; push CX
		xchg	ax,cx		; CH <- push register AH

; ------------- Unpack number in AL

		mov	cl,4		; CL <- number of rotations
		mov	ah,al		; AH <- number to unpack
		shr	ah,cl		; AH = BCD digit HIGH
		and	al,0fh		; AL = BCD digit LOW
		aad			; pack digits to binary

; ------------- Pop registers

		mov	ah,ch		; pop register AH
		pop	cx		; pop CX
		ret

; ----------------------------------------------------------------------------
;                      Prepare date in DOS file format
; ----------------------------------------------------------------------------
; INPUT:	DS = data segment
; ----------------------------------------------------------------------------

; ------------- Push registers

CalcFileDate:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX

; ------------- Prepare date

		mov	ax,[Year]	; AX <- year
		sub	ax,1980		; offset from 1980
		mov	cl,9		; CL <- 9 number of rotations
		shl	ax,cl		; shift year to bit 9
		xchg	ax,bx		; BX <- year

		mov	al,[Month]	; AL <- month
		cbw			; AX <- month
		mov	cl,5		; CL <- 5 number of rotations
		shl	ax,cl		; shift month to bit 5
		or	ax,bx		; add year

		or	al,[Day]	; add day
		mov	[FileDate],ax	; store date in DOS file format

; ------------- Pop registers

		pop	cx		; pop CX
		pop	bx		; pop BX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                         Read system timer
; ----------------------------------------------------------------------------
; OUTPUT:	CX:DX = system timer (number of 1/18 sec ticks)
; NOTES:	It shifts "current date" when timer overflows 24 hours.
; ----------------------------------------------------------------------------

; ------------- Push registers

GetTimer:	push	ax		; push AX

; ------------- Read system timer

		mov	ah,0		; AH <- function code
		int	1ah		; read system timer
		or	al,al		; shift day on midnight?
		jz	GetTimer8	; no

; ------------- Push registers 2

		push	bx		; push BX
		push	cx		; push CX
		push	ds		; push DS

; ------------- Prepare data segment

		push	cs		; push CS
		pop	ds		; DS <- CS

; ------------- Prepare days in February

		mov	cx,[Year]	; CX <- year
		call	PrepareFeb	; prepare days in February

; ------------- Increase day

		inc	byte [Day]	; increase day
		mov	al,[Month]	; AL <- month
		cbw			; AX <- month
		xchg	ax,bx		; BX <- month
		mov	al,[Day]	; AL <- day
		cmp	al,[bx+DayMonthTab-1] ; check day
		jbe	GetTimer6	; day is OK

; ------------- Increase month

		mov	byte [Day],1	; correct day in month
		inc	byte [Month]	; increase month
		cmp	byte [Month],12	; maximal month
		jbe	GetTimer6	; month is OK

; ------------- Increase year

		mov	byte [Month],1	; correct month
		inc	word [Year]	; increase year

; ------------- Prepare date in DOS file format

GetTimer6:	call	CalcFileDate	; prepare date in DOS file format

; ------------- Pop registers 2

		pop	ds		; pop DS
		pop	cx		; pop CX
		pop	bx		; pop BX

; ------------- Pop registers

GetTimer8:	pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                  Recalculate system timer to time
; ----------------------------------------------------------------------------
; INPUT:	CX:DX = timer
; OUTPUT:	CL = hundredth
;		CH = second
;		AL = minute
;		AH = hour
; DESTROYS:	BX, DX
; ----------------------------------------------------------------------------

; ------------- Calculate CX:DX * 5 (-> DX:AX, max. 7865195)

Clock2Time:	mov	bx,5		; BX <- 5
		xchg	ax,dx		; AX <- timer LOW
		xchg	ax,cx		; AX <- timer HIGH, CX <- timer LOW
		mul	bx		; AX <- timer HIGH*5
		xchg	ax,cx		; AX <- timer LOW, CX <- timer HIGH*5
		mul	bx		; DX:AX <- timer LOW*5
		add	dx,cx		; add timer HIGH

; ------------- Calculate DX:AX / 59659 * 65536 (-> CX:AX, max. 8639994)

		mov	bx,59659	; BX <- 59659
		div	bx		; AX <- quotient, DX <- remainder
		xchg	cx,ax		; CX <- hundredths HIGH
		xor	ax,ax		; AX <- 0, DX:AX = remainder * 65536
		div	bx		; AX <- hundredths LOW

; ------------- Calculate seconds (->DX:AX, max.86399)+hundredths (->CL, 0-99)

		xchg	ax,cx		; AX <- hundredths HIGH, CX <- LOW
		xor	dx,dx		; DX <- 0
		mov	bx,100		; BX <- divisor
		div	bx		; AX <- seconds HIGH, DX <- reaminder
		xchg	ax,cx		; AX <- hundredths LOW, CX <- sec. HIGH
		div	bx		; AX <- seconds LOW, DX <- hundredths
		xchg	dx,cx		; DX <- seconds HIGH, CL <- hundredths

; ------------- Calculate second (-> CH, 0 to 59)+minutes (-> AX, max. 1439)

		mov	bl,60		; BX <- divisor
		div	bx		; calculate minute and second
		mov	ch,dl		; CH <- second

; ------------- Calculate hour (0 to 23) and minute (0 to 59)

		div	bl		; AL <- hour, AH <- minute
		xchg	ah,al		; AL <- minute, AH <- hour
		ret

; ----------------------------------------------------------------------------
;                  Recalculate time to system timer
; ----------------------------------------------------------------------------
; INPUT:	BL = minute
;		BH = hour
;		CL = hundredth
;		CH = second
; OUTPUT:	CX:DX = timer
; DESTROYS:	AX, BX
; ----------------------------------------------------------------------------

; ------------- Merge second with hundredth (-> CX, max. 5999 hundredths)

Time2Clock:	mov	al,100		; AL <- 100 hundredths in second
		mul	ch		; AX <- second in hundredths
		mov	ch,0		; CX = hundredth
		add	cx,ax		; CX <- second*100 + hundredth

; ------------- Merge minute with hour (-> AX, max. 1439 minutes)

		mov	al,60		; AL <- 60 minutes in hour
		mul	bh		; AX <- recalc hour to minutes
		mov	bh,0		; BX = minute
		add	ax,bx		; AX = hour*60 + minute

; ------------- Merge all items (-> DX:CX, max. 8639999 hundredths)

		mov	dx,6000		; DX <- 6000 hundredths in minute
		mul	dx		; DX:AX <- hour & minute in hundredths
		add	cx,ax		; CX <- hundredths LOW
		adc	dx,byte 0	; DX <- hundredths HIGH

; ------------- Calculate DX:CX * 59659 / 65536 (-> DX:AX, max. 7865199)

		xchg	ax,dx		; AX <- hundredths HIGH
		xchg	ax,cx		; AX <- hundredths LOW, CX <- HIGH
		mov	bx,59659	; BX <- 59659
		mul	bx		; DX <- result LOW (e.g. / 65536)
		xchg	ax,dx		; AX <- result LOW
		xchg	ax,cx		; CX <- result LOW, AX <- hundr. HIGH
		mul	bx		; DX:AX <- result
		add	ax,cx		; AX <- result LOW
		adc	dx,byte 0	; DX <- result HIGH

; ------------- Calculate DX:AX / 5 (-> CX:DX, max. 1573039)

		mov	bx,5		; BX <- divisor
		xchg	ax,dx		; AX <- HIGH (= max. 24)
		div	bl		; AL <- result HIGH
		xchg	ax,cx		; CL <- result HIGH
		mov	al,ch		; AL <- remainder
		mov	ch,0		; CX = result HIGH
		cbw			; AX = remainder
		xchg	ax,dx		; AX <- LOW, DX <- HIGH
		div	bx		; calculate result LOW
		xchg	ax,dx		; DX <- result LOW		
		ret

; ----------------------------------------------------------------------------
;                       Prepare days in February
; ----------------------------------------------------------------------------
; INPUT:	CL = year (may be absolute or relative from 1980 or 1900)
; ----------------------------------------------------------------------------

PrepareFeb:	push	ax		; push AX
		mov	al,28		; AL <- 28 days in non-leap year
		test	cl,3		; is it leap year?
		jnz	PrepareFeb2	; it is not leap year
		inc	ax		; AL <- 29 days in leap year
PrepareFeb2:	mov	[cs:DayMonthFeb],al; store days in February
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                   Int 21h, function 2Ah - Get system date
; ----------------------------------------------------------------------------
; INT21 INPUT:	AH = 2Ah (function code)
; INT21 OUTPUT:	CX = year (1980-2099)
;		DH = month (1-12)
;		DL = day (1-31)
; ----------------------------------------------------------------------------

; ------------- Read system timer (to shift current day)

Int212A:	call	GetTimer	; read system timer

; ------------- Return current date

		mov	cx,[Year]	; CX <- year
		call	SetRegCX	; set year
		mov	dx,[DayMonth]	; DL <- day, DH <- month
		call	SetRegDX	; set day and month
		mov	al,0		; AL <- 0 day of week is invalid
		ret

; ----------------------------------------------------------------------------
;                   Int 21h, function 2Bh - Set system date
; ----------------------------------------------------------------------------
; INT21 INPUT:	AH = 2Bh (function code)
;		CX = year (1980-2099)
;		DH = month (1-12)
;		DL = day (1-31)
; INT21 OUTPUT:	AL = result
;			0: successful
;			0ffh: invalid date, system date unchanged
; ----------------------------------------------------------------------------

; ------------- Prepare data segment

Int212B:	push	cs		; push CS
		pop	ds		; DS <- CS

; ------------- Check year

		mov	al,0ffh		; AL <- 0ffh, invalid date flag
		cmp	cx,1980		; minimal year
		jb	Int212B8	; invalid year
		cmp	cx,2099		; maximal year
		ja	Int212B8	; invalid year

; ------------- Check month

		or	dh,dh		; minimal month
		jz	Int212B8	; invalid month
		cmp	dh,12		; maximal month
		ja	Int212B8	; invalid month

; ------------- Prepare days in February

		push	cx		; push CX
		sub	cx,1980		; CX <- offset from 1980
		call	PrepareFeb	; prepare February
		pop	cx		; pop CX

; ------------- Check day

		or	dl,dl		; minimal day
		jz	Int212B8	; invalid day
		push	bx		; push BX
		xor	bx,bx		; BX <- 0
		mov	bl,dh		; BL <- month
		cmp	dl,[cs:bx+DayMonthTab-1] ; check days in month
		pop	bx		; pop BX
		ja	Int212B8	; invalid day

; ------------- Read system timer (to flush midnight flag)

		push	cx		; push CX
		push	dx		; push DX
		call	GetTimer	; read system timer
		pop	dx		; pop DX
		pop	cx		; pop CX

; ------------- Store system date

		mov	[Year],cx	; store year
		mov	[DayMonth],dx	; store day and month

; ------------- Split year into century and year

		mov	al,100		; AL <- 100 years in century
		xchg	ax,cx		; AX <- year, CL <- 100
		div	cl		; split into year and century
		xchg	al,ah		; AL <- year, AH <- century

; ------------- Set new date to RTC clock

		call	BinBCDD		; pack to BCD
		xchg	ax,cx		; CX <- year
		mov	ah,5		; AH <- function code
		int	1ah		; set new date

; ------------- Prepare date in DOS file format

		call	CalcFileDate	; recalc to DOS file format
		mov	al,0		; status OK
Int212B8:	ret

; ----------------------------------------------------------------------------
;                   Int 21h, function 2Ch - Get system time
; ----------------------------------------------------------------------------
; INT21 INPUT:	AH = 2Ch (function code)
; INT21 OUTPUT:	CH = hour (0 to 23)
;		CL = minute (0 to 59)
;		DH = second (0 to 59)
;		DL = 1/100 seconds (0 to 99)
; NOTES: Time resolution is 55 ms. On some systems DL may return 0.
; ----------------------------------------------------------------------------

; ------------- Read system timer

Int212C:	call	GetTimer	; read system timer

; ------------- Recalc to time

		call	Clock2Time	; recalc timer to time
		xchg	ax,cx		; CH <- hour, CL <- minute
		xchg	ax,dx		; DH <- second, DL <- hundredth

; ------------- Return current time

		call	SetRegCX	; set minute and hour
		call	SetRegDX	; set hundredth and second
		mov	al,0		; return code OK
		ret

; ----------------------------------------------------------------------------
;                   Int 21h, function 2Dh - Set system time
; ----------------------------------------------------------------------------
; INT21 INPUT:	AH = 2Dh (function code)
; 		CH = hour (0 to 23)
;		CL = minute (0 to 59)
;		DH = second (0 to 59)
;		DL = 1/100 seconds (0 to 99)
; INT21 OUTPUT:	AL = result
;			0: successful
;			0ffh: invalid time, system time unchanged
; ----------------------------------------------------------------------------

; ------------- Check time

Int212D:        mov	al,0ffh		; AL <- 0ffh, invalid time flag
		cmp	ch,23		; maximal hour
		ja	Int212D8	; invalid hour
		cmp	cl,59		; maximal minute
		ja	Int212D8	; invalid minute
		cmp	dh,59		; maximal second
		ja	Int212D8	; invalid second
		cmp	dl,99		; maximal hundredth
		ja	Int212D8	; invalid hundredth

; ------------- Set new time to RTC clock

		push	cx		; push CX (CL=minute, CH=hour)
		push	dx		; push DX (DL=hundredth, DH=second)
		xchg	ax,cx		; AX <- AL=minute, AH=hour
		call	BinBCDD		; pack to BCD
		xchg	ax,cx		; CL <- minute, CH <- hour
		mov	dl,0		; no daylight savings
		mov	ah,3		; AH <- function code
		int	1ah		; set current time

; ------------- Read system timer (to flush midnight flag)

		call	GetTimer	; read system timer
		pop	cx		; pop CX (CL=hundredth, CH=second)
		pop	bx		; pop BX (BL=minute, BH=hour)

; ------------- Recalculate time to system timer (-> CX:DX)

		call	Time2Clock	; recalc time to system timer

; ------------- Set new time to system timer

		mov	ah,1		; AH <- function code
		int	1ah		; set new time
		mov	al,0		; return code OK
Int212D8:	ret

; ----------------------------------------------------------------------------
;                                    Data
; ----------------------------------------------------------------------------

; ------------- Current date

DayMonth:
Day:		db	1		; current day (1 to 31)
Month:		db	1		; current month
Year:		dw	1980		; current year (1980 to 2099)

FileDate:	dw	0		; current date in DOS file format

; ------------- Days in months

DayMonthTab:	db	31		; January
DayMonthFeb:	db	28		; February
		db	31		; March
		db	30		; April
		db	31		; May
		db	30		; June
		db	31		; July
		db	31		; August
		db	30		; September
		db	31		; October
		db	30		; November
		db	31		; December

Zpět na stránku systému MICRODOS