ptime.asm
上传用户:xiaoan1112
上传日期:2013-04-11
资源大小:19621k
文件大小:19k
源码类别:

操作系统开发

开发平台:

Visual C++

  1. ;
  2. ;------------------------------------------------------------------------------
  3. ;M074 - ptime.asm added, containing clock/time routines for power.asm.
  4. ;
  5. ;   09/11/91  SMR M077: B#2669. Registered POWER's 2f channels in mult.inc
  6. ;
  7. ;   09/25/91  NSM M090: B#2729. Try to update our time from CMOS under 
  8. ; WIN ENH mode once in 1024 I1c ticks. 
  9. ; (approx. once in a minute)
  10. ; This update happens only if DOS calls us for time and
  11. ; does not exactly happen once in a minute.
  12. ;
  13. ; (this is changed to 20 secs from 1 minute)
  14. ;
  15. ;  11/26/91   NSM M101: We lose date sometimes under windows. To fix this
  16. ; do Int 1a's to get tick count instead of looking at 40:
  17. ; 6ch and if we get rollover, then go & update date 
  18. ; and time from CMOS.
  19. ;------------------------------------------------------------------------------
  20. ;
  21. ;
  22. .xlist
  23. include version.inc     ; set build flags
  24. IFDEF   POWER ; generate code only if power management
  25. ; is enabled
  26. IFNDEF  POWERALONE              ; segment declarations for resident version
  27. include biosseg.inc     ; establish bios segment structure
  28. ELSE                            ; segment declarations for standalonde version
  29. .SEQ
  30. Bios_Code       segment word public 'Bios_Code'
  31. Bios_Code       ends
  32. Bios_Data       segment word public 'Bios_Data'
  33. Bios_Data       ends
  34. SysInitSeg      segment word public 'system_init'
  35. SysInitSeg      ends
  36. ; following segment definitions used by transient part of code
  37. ENDIF
  38. include msequ.inc
  39. include devsym.inc
  40. include bpb.inc
  41. include ioctl.inc
  42. include mult.inc ; M077
  43. include power.inc
  44. IFDEF INCL_APM
  45. include apmequ.inc ; M001
  46. ENDIF
  47. break   macro
  48. endm
  49. include error.inc
  50. .list
  51. include msgroup.inc     ; define Bios_Data segment
  52. extrn month_table:word
  53. IFDEF   POWERALONE                      ; standalone device driver version
  54. Bios_Res        dw      Bios_Code       ; Our code segment address
  55. ELSE                                    ; resident BIOS version
  56. extrn   Bios_Res:word           ; Code segment address supplied externally
  57. extrn ttticks:dword ; far ptr to time_to_ticks routine
  58. extrn bintobcd:dword ; ptr to bin_to_bcd routine
  59. IFDEF INCL_APM
  60. extrn Check_and_Init_APM_Ptr:dword ; ptr to APM init routine
  61. ENDIF ;INCL_APM
  62. extrn P_UpdFromCMOS_Ptr:dword ; ptr to CMOS clock read ; M081
  63. ENDIF ;NOT POWERALONE
  64. extrn daycnt:word ; extrns for both resident and stand-alone
  65. extrn daycnt2:word ; versions
  66. extrn base_century:byte
  67. extrn base_year:byte
  68. extrn month_tab:byte
  69. extrn bin_date_time:byte
  70. extrn CMOSUpdFlg:byte
  71. extrn CMOSPollCount:word
  72. tocode
  73. IFDEF POWERALONE ; stand alone version
  74. Bios_Data_Word  dw      Bios_Data               ; Our data segment
  75. bintobcd proc near ;for real time clock support
  76. ;convert a binary input in al (less than 63h or 99 decimal)
  77. ;into a bcd value in al.  ah destroyed.
  78. push cx
  79. aam ; M048
  80. mov cl, 4 ; M048
  81. shl ah, cl ; M048
  82. or al, ah ; M048
  83. pop cx
  84. ret
  85. bintobcd endp
  86. ELSE ; resident version
  87. extrn Bios_Data_word:word
  88. ENDIF
  89. public tim_read
  90. public tim_writ
  91. ;--------------------------------------------------------------------
  92. ;
  93. ; tim_writ sets the current time
  94. ;
  95. ; on entry es:[di] has the current time:
  96. ;
  97. ; number of days since 1-1-80 (word)
  98. ; minutes (0-59) (byte)
  99. ; hours (0-23) (byte)
  100. ; hundredths of seconds (0-99) (byte)
  101. ; seconds (0-59) (byte)
  102. ;
  103. ; each number has been checked for the correct range.
  104. ;
  105. tim_writ proc near
  106. assume ds:Bios_Data
  107. mov ax,word ptr es:[di]
  108. push ax ;daycnt. we need to set this at the very
  109. ;  end to avoid tick windows.
  110. ; Set hardware clock time.
  111. mov al,es:[di+3] ;get binary hours
  112. call bintobcd ;convert to bcd
  113. mov ch,al ;ch = bcd hours
  114. mov al,es:[di+2] ;get binary minutes
  115. call bintobcd ;convert to bcd
  116. mov cl,al ;cl = bcd minutes
  117. mov al,es:[di+5] ;get binary seconds
  118. call bintobcd ;convert to bcd
  119. mov dh,al ;dh = bcd seconds
  120. mov dl,0 ;dl = 0 (st) or 1 (dst)
  121. cli ;turn off timer
  122. mov ah,03h ;set rtc time
  123. int 1ah ;call rom bios clock routine
  124. sti
  125. mov cx,word ptr es:[di+2]
  126. mov dx,word ptr es:[di+4]
  127. IFDEF POWERALONE
  128. call time_to_ticks
  129. ELSE
  130. call ttticks
  131. ENDIF
  132. ;cx:dx now has time in ticks
  133. cli ; turn off timer
  134. mov ah, 1 ; command is set time in clock
  135. int 1ah ; call rom-bios clock routines
  136. pop [daycnt]
  137. sti
  138. call daycnttoday ; convert to bcd format
  139. cli ; turn off timer
  140. mov ah,05h ; set rtc date
  141. int 1ah ; call rom-bios clock routines
  142. sti
  143. clc
  144. ret
  145. tim_writ endp
  146. ;
  147. ; gettime reads date and time
  148. ; and returns the following information:
  149. ; es:[di]  =count of days since 1-1-80
  150. ; es:[di+2]=hours
  151. ; es:[di+3]=minutes
  152. ; es:[di+4]=seconds
  153. ; es:[di+5]=hundredths of seconds
  154. tim_read proc near
  155. ; M090 BEGIN - See if we have to update our time from CMOS before 
  156. ; returning date and time to caller.
  157. cmp [CMOSUpdFlg],0 ; M090 do we need to update from CMOS
  158. je tr_NoCMOSUpdate ; 
  159. tr_CMOSUpd: ; M101
  160. IFDEF POWERALONE ; M081
  161. call far ptr P_UpdFromCMOS
  162. ELSE
  163. call    P_UpdFromCMOS_ptr    ; M074 update our date and time
  164. ; from CMOS RTC
  165. ENDIF
  166. mov [CMOSPollCount],MAXCMOSPOLLCOUNT
  167. mov [CMOSUpdFlg],0 ; 
  168. ; M090 END
  169. tr_NoCMOSUpdate:
  170. ; M101 - BEGIN - get tick count through 1a instead of looking at 40:6ch
  171. ; and check for rollover
  172. mov ax,0 ; get tick count
  173. int 1ah ; cx:dx = tick count
  174. or al,al ; al != 0 if midnight passed
  175. jnz tr_CMOSUpd ; rollover; update date and time
  176. ; M101 - END
  177. mov si,[daycnt]
  178. ; we now need to convert the time in tick to the time in 100th of
  179. ; seconds.  the relation between tick and seconds is:
  180. ;
  181. ;  65536 seconds
  182. ;        ----------------
  183. ; 1,193,180 tick
  184. ;
  185. ; to get to 100th of second we need to multiply by 100. the equation is:
  186. ;
  187. ; ticks from clock  * 65536 * 100
  188. ;      ---------------------------------  = time in 100th of seconds
  189. ; 1,193,180
  190. ;
  191. ; fortunately this fromula simplifies to:
  192. ;
  193. ; ticks from clock * 5 * 65,536
  194. ;      --------------------------------- = time in 100th of seconds
  195. ; 59,659
  196. ;
  197. ; the calculation is done by first multipling tick by 5. next we divide by
  198. ; 59,659.  in this division we multiply by 65,536 by shifting the dividend
  199. ; my 16 bits to the left.
  200. ;
  201. ; start with ticks in cx:dx
  202. ; multiply by 5
  203. mov ax,cx
  204. mov bx,dx
  205. shl dx,1
  206. rcl cx,1 ;times 2
  207. shl dx,1
  208. rcl cx,1 ;times 4
  209. add dx,bx
  210. adc ax,cx ;times 5
  211. xchg ax,dx
  212. ; now have ticks * 5 in dx:ax
  213. ; we now need to multiply by 65,536 and divide by 59659 d.
  214. mov cx,59659 ; get divisor
  215. div cx
  216. ; dx now has remainder
  217. ; ax has high word of final quotient
  218. mov bx,ax ; put high work if safe place
  219. xor ax,ax ; this is the multiply by 65536
  220. div cx ; bx:ax now has time in 100th of seconds
  221. ;rounding based on the remainder may be added here
  222. ;the result in bx:ax is time in 1/100 second.
  223. mov dx,bx
  224. mov cx,200 ;extract 1/100's
  225. ;division by 200 is necessary to ensure no overflow--max result
  226. ;is number of seconds in a day/2 = 43200.
  227. div cx
  228. cmp dl,100 ;remainder over 100?
  229. jb noadj
  230. sub dl,100 ;keep 1/100's less than 100
  231. noadj:
  232. cmc ;if we subtracted 100, carry is now set
  233. mov bl,dl ;save 1/100's
  234. ;to compensate for dividing by 200 instead of 100, we now multiply
  235. ;by two, shifting a one in if the remainder had exceeded 100.
  236. rcl ax,1
  237. mov dl,0
  238. rcl dx,1
  239. mov cx,60 ;divide out seconds
  240. div cx
  241. mov bh,dl ;save the seconds
  242. div cl ;break into hours and minutes
  243. xchg al,ah
  244. ;time is now in ax:bx (hours, minutes, seconds, 1/100 sec)
  245. push ax
  246. mov ax,si ; daycnt
  247. stosw
  248. pop ax
  249. stosw
  250. mov ax,bx
  251. stosw
  252. clc
  253. ret
  254. tim_read endp
  255. assume es:nothing
  256. ; the following routine is executed at resume time when the system
  257. ; powered on after suspension. it reads the real time clock and
  258. ; resets the system time and date
  259. ;
  260. ; This can be patched to be the INT6C vector so that this can be
  261. ; used by other people to update DOS time from CMOS (after taking
  262. ; care for IRET)
  263. public P_UpdFromCMOS
  264. P_UpdFromCMOS proc far
  265. assume ds:nothing
  266. push ds
  267. mov ds,cs:Bios_Data_Word
  268. assume ds:Bios_Data
  269. call read_real_date ; get the date from the clock
  270. PUFC_UpdDate: ; M101
  271. mov ds:daycnt,si ; update our copy of date
  272. call read_real_time ; get the time from the rtc
  273. cli
  274. mov ah,01h ; command to set the time
  275. int 1ah ; call rom-bios time routine
  276. sti
  277. ; M101 BEGIN - check back to see if date changed when we were reading the
  278. ; time; if so, update date and time all over again ( Paranoid?)
  279. call read_real_date ; get the date from the clock
  280. ; BUGBUG- nagara - Store the ret.value of date from int 1a in this
  281. ; procedure read_real_date so that at the end we don't really have to
  282. ; call read_real_date again; we just need to call int 1a and compare the
  283. ; date registers against the stored values of these registers.
  284. cmp si,ds:daycnt ; is the date changed ?
  285. jne PUFC_UpdDate ; yes, go back and set the new date
  286. ; M101 END
  287. pop ds
  288. ret
  289. P_UpdFromCMOS endp
  290. ;************************************************************************
  291. ;
  292. ;   read_real_date reads real-time clock for date and returns the number
  293. ;   of days elapsed since 1-1-80 in si
  294. ;
  295. read_real_date proc near
  296. assume ds:Bios_Data,es:nothing
  297. push ax
  298. push cx
  299. push dx
  300. xor ah,ah ; throw away clock roll over
  301. int 1ah
  302. pop dx
  303. pop cx
  304. pop ax ; cas - bad code!
  305. push ax
  306. push bx
  307. push cx
  308. push dx
  309. mov daycnt2,1 ; real time clock error flag (+1 day)
  310. mov ah,4 ; read date function code
  311. int 1ah ; read real-time clock
  312. jnc read_ok  ; jmp success
  313. jmp r_d_ret  ; jmp error
  314. read_ok: ; ******* get bcd values in binary *****
  315. mov word ptr bin_date_time+0,cx  ; store as hex value
  316. mov word ptr bin_date_time+2,dx  ; ...
  317. mov daycnt2,2 ; read of r-t clock successful
  318. call bcd_verify ; verify bcd values in range
  319. jc r_d_ret  ; jmp some value out of range
  320. mov daycnt2,3 ; read of r-t clock successful
  321. call date_verify ; verify date values in range
  322. jc r_d_ret  ; jmp some value out of range
  323. mov daycnt2,0 ; verify successful
  324. call in_bin ; convert date to binary
  325. ; ******* years since 1-1-80 *********
  326. mov al,byte ptr bin_date_time    ; get years into century
  327. cbw      ;
  328. cmp byte ptr bin_date_time+1,20  ; 20th century?
  329. jnz century_19      ; jmp no
  330. add ax,100 ; add in a century
  331. century_19: ;
  332. sub ax,80 ; subtract off 1-1-80
  333. mov cl,4 ; leap year every 4
  334. div cl ; al= # leap year blocks, ah= remainder
  335. mov bl,ah ; save odd years
  336. cbw ; zero ah
  337. mov cx,366+3*365 ; # of days in leap year blocks
  338. mul cx ; dx:ax is result
  339. mov daycnt2,ax ; save count of days
  340. mov al,bl ; get odd years count
  341. cbw ;
  342. or ax,ax ; is ax= 0?
  343. jz leap_year ; jmp if none
  344. mov cx,365 ; days in year
  345. mul cx ; dx:ax is result
  346. add daycnt2,ax ; add on days in odd years
  347. jmp short leap_adjustment ; account for leap year
  348. leap_year: ; possibly account for a leap day
  349. cmp byte ptr bin_date_time+3,2 ; is month february
  350. jbe no_leap_adjustment ; jan or feb. no leap day yet.
  351. leap_adjustment: ; account for leap day
  352. inc daycnt2
  353. no_leap_adjustment: ; ******* get days of month *******
  354. mov cl,byte ptr bin_date_time+2
  355. xor ch,ch
  356. dec cx ; because of offset from day 1, not day 0
  357. add daycnt2,cx  ; ******* get days in months preceeing *****
  358. mov cl,byte ptr bin_date_time+3   ; get month
  359. xor ch,ch
  360. dec cx ; january starts at offset 0
  361. shl cx,1 ; word offset
  362. mov si,offset month_table ; beginning of month_table
  363. add si,cx ; point into month table
  364. mov ax,word ptr [si]; get # days in previous months
  365. add daycnt2,ax
  366. r_d_ret:
  367. mov si,daycnt2  ; result in si
  368. pop dx
  369. pop cx
  370. pop bx
  371. pop ax
  372. ret
  373. r_t_retj:
  374. xor cx,cx
  375. xor dx,dx
  376. jmp short r_t_ret
  377. read_real_date endp
  378. ;--------------------------------------------------------------------
  379. ; read_real_time reads the time from the rtc. on exit, it has the number of
  380. ; ticks (at 18.2 ticks per sec.) in cx:dx.
  381. read_real_time proc near
  382. assume ds:Bios_Data,es:nothing
  383. mov ah,2
  384. int 1ah
  385. jc r_t_retj
  386. oktime:
  387. mov word ptr bin_date_time,cx ; hours + minutes
  388. mov byte ptr bin_date_time+3,dh ; seconds
  389. mov byte ptr bin_date_time+2,0 ; unused for time
  390. call bcd_verify
  391. jc r_t_retj
  392. call time_verify
  393. jc r_t_retj
  394. call in_bin
  395. mov cx,word ptr bin_date_time
  396. mov dx,word ptr bin_date_time+2
  397. ; get time in ticks in cx:dx
  398. IFDEF POWERALONE
  399. call time_to_ticks
  400. ELSE
  401. call ttticks
  402. ENDIF
  403. r_t_ret:
  404. ret
  405. read_real_time endp
  406. ;--------------------------------------------------------------------
  407. ;   in_bin converts bin_date_time values from bcd to bin
  408. in_bin proc near
  409. assume ds:Bios_Data,es:nothing
  410. mov al,byte ptr bin_date_time+0  ; years or minutes 
  411. call bcd_to_bin
  412. mov byte ptr bin_date_time+0,al
  413. mov al,byte ptr bin_date_time+1  ;century or hours
  414. call bcd_to_bin
  415. mov byte ptr bin_date_time+1,al
  416. mov al,byte ptr bin_date_time+2  ; days (not used for time)
  417. call bcd_to_bin
  418. mov byte ptr bin_date_time+2,al
  419. mov al,byte ptr bin_date_time+3  ; months or seconds
  420. call bcd_to_bin
  421. mov byte ptr bin_date_time+3,al
  422. ret
  423. in_bin endp
  424. ;--------------------------------------------------------------------
  425. ;   bcd_to_bin converts two bcd nibbles in al (value <= 99.) to
  426. ;   a binary representation in al
  427. ;   ah is destroyed
  428. bcd_to_bin proc near
  429. assume ds:nothing,es:nothing
  430. mov ah, al ; M048
  431. and al, 0fh ; M048
  432. mov cl, 4 ; M048
  433. shr ah, cl ; M048
  434. aad ; M048
  435. ret
  436. bcd_to_bin endp
  437. ;--------------------------------------------------------------------
  438. ;   date_verify loosely checks bcd date values to be in range in bin_date_time
  439. date_verify proc near
  440. assume ds:Bios_Data,es:nothing
  441. cmp byte ptr bin_date_time+1,20h  ; century check
  442. ja date_error       ; error
  443. jz century_20       ; jmp in 20th century
  444. cmp byte ptr bin_date_time+1,19h  ; century check
  445. jb date_error       ;  error
  446. cmp byte ptr bin_date_time+0,80h  ; year check
  447. jb date_error       ;  error
  448. century_20:
  449. cmp byte ptr bin_date_time+0,99h  ; year check
  450. ja date_error       ;  error
  451. cmp byte ptr bin_date_time+3,12h  ; month check
  452. ja date_error       ;  error
  453. cmp byte ptr bin_date_time+3,00h  ; month check
  454. jbe date_error       ;  error
  455. cmp byte ptr bin_date_time+2,31h  ; day check
  456. ja date_error       ;  error
  457. cmp byte ptr bin_date_time+2,00h  ; day check
  458. jbe date_error       ;  error
  459. clc       ; set success flag
  460. ret
  461. date_error:
  462. stc       ; set error flag
  463. ret
  464. date_verify endp
  465. ;--------------------------------------------------------------------
  466. ; time_verify very loosely checks bcd date values to be in range in bin_date_time
  467. time_verify proc near
  468. assume ds:Bios_Data,es:nothing
  469. cmp byte ptr bin_date_time+1,24h
  470. ja time_error
  471. cmp byte ptr bin_date_time+0,59h
  472. ja time_error
  473. cmp byte ptr bin_date_time+3,59h
  474. ja time_error
  475. clc
  476. ret
  477. time_error:
  478. stc
  479. ret
  480. time_verify endp
  481. ;--------------------------------------------------------------------
  482. ;   bcd_verify checks values in bin_date_time to be valid
  483. ;   bcd numerals.  carry set if any nibble out of range
  484. bcd_verify proc near
  485. assume ds:Bios_Data,es:nothing
  486. mov cx,4 ; 4 bytes to check
  487. mov bx,offset bin_date_time
  488. bv_loop:
  489. mov al,[bx]  ; get a bcd number (0..99)
  490. mov ah,al
  491. and ax,0f00fh ; 10's place in high ah, 1's in al
  492. cmp al,10 ; is 1's place in range?
  493. ja bv_error ; jmp out of range
  494. shr ah,1 ; swap nibbles
  495. shr ah,1
  496. shr ah,1
  497. shr ah,1
  498. and ah,0fh ; get rid of any erroneous bits
  499. cmp ah,10 ; is 10's place in range
  500. ja bv_error ; jmp out of range
  501. inc bx ; next byte
  502. dec cx
  503. jnz bv_loop
  504. clc ; set success flag
  505. ret
  506. bv_error:
  507. stc ; set error flag
  508. ret
  509. bcd_verify endp
  510. ;--------------------------------------------------------------------
  511. daycnttoday proc near ; for real time clock support
  512. ;entry: [daycnt] = number of days since 1-1-80
  513. ;
  514. ;return: ch - centry in bcd
  515. ;  cl - year in bcd
  516. ;  dh - month in bcd
  517. ;  dl - day in bcd
  518. push di
  519. mov di,daycnt
  520. cmp di,(365*20+(20/4)) ;# of days from 1-1-1980 to 1-1-2000
  521. jae century20
  522. mov base_century,19
  523. mov base_year,80
  524. jmp short years
  525. century20: ;20th century
  526. mov base_century,20
  527. mov base_year,0
  528. sub di,(365*20+(20/4)) ;adjust daycnt
  529. years:
  530. xor dx,dx
  531. mov ax,di
  532. mov bx,(366+365*3) ;# of days in a leap year block
  533. div bx ;ax = # of leap block, dx = daycnt
  534. mov di,dx ;save daycnt left
  535. mov bl,4
  536. mul bl ;ax = # of years. less than 100 years!
  537. add base_year,al ;so, ah = 0. adjust year accordingly.
  538. inc di ;set daycnt to 1 base
  539. cmp di,366 ;the daycnt here is the remainder of the leap year block.
  540. jbe leapyear ;so, it should within 366+355+355+355 days.
  541. inc base_year ;first if daycnt <= 366, then leap year
  542. sub di,366 ;else daycnt--, base_year++;
  543. ;and the next three years are regular years.
  544. mov cx,3
  545. regularyear:
  546. cmp di,365 ;for(i=1; i>3 or daycnt <=365;i++)
  547. jbe yeardone ;{if (daycnt > 365)
  548. inc base_year ;  { daycnt -= 365
  549. sub di,365 ;  }
  550. loop regularyear ;}
  551. ; should never fall through loop
  552. leapyear:
  553. mov byte ptr month_tab+1,29 ;leap year. change the month table.
  554. yeardone:
  555. xor bx,bx
  556. xor dx,dx
  557. mov ax,di
  558. mov si,offset month_tab
  559. mov cx,12
  560. months:
  561. inc bl
  562. mov dl,byte ptr ds:[si] ;compare daycnt for each month until fits
  563. cmp ax,dx ;dh=0.
  564. jbe month_done
  565. inc si ;next month
  566. sub ax,dx ;adjust daycnt
  567. loop months
  568. ; should never fall through loop
  569. month_done:
  570. mov byte ptr month_tab+1,28 ;restore month table value
  571. mov dl,bl
  572. mov dh,base_year
  573. mov cl,base_century  ;now, al=day, dl=month,dh=year,cl=century
  574. call bintobcd ;oh my!!! to save 15 bytes, bin_to_bcd proc
  575. ;was relocated seperately from daycnt_to_day proc.
  576. xchg dl,al ;dl = bcd day, al = month
  577. call bintobcd
  578. xchg dh,al ;dh = bcd month, al = year
  579. call bintobcd
  580. xchg cl,al ;cl = bcd year, al = century
  581. call bintobcd
  582. mov ch,al ;ch = bcd century
  583. pop di ;restore original value
  584. ret
  585. daycnttoday endp
  586. IFDEF POWERALONE ; needed only for standalone version
  587. ; for resident version use the one in 
  588. ; mschar.asm
  589. ;--------------------------------------------------------------------
  590. ; convert time to ticks
  591. ; input : time in cx and dx
  592. ; ticks returned in cx:dx
  593. time_to_ticks proc near
  594. ; first convert from hour,min,sec,hund. to
  595. ; total number of 100th of seconds
  596. mov al,60
  597. mul ch ;hours to minutes
  598. mov ch,0
  599. add ax,cx ;total minutes
  600. mov cx,6000  ;60*100
  601. mov bx,dx ;get out of the way of the multiply
  602. mul cx ;convert to 1/100 sec
  603. mov cx,ax
  604. mov al,100
  605. mul bh ;convert seconds to 1/100 sec
  606. add cx,ax ;combine seconds with hours and min.
  607. adc dx,0 ;ripple carry
  608. mov bh,0
  609. add cx,bx ;combine 1/100 sec
  610. adc dx,0
  611. ; dx:cx is time in 1/100 sec
  612. xchg ax,dx
  613. xchg ax,cx ;now time is in cx:ax
  614. mov bx,59659
  615. mul bx ;multiply low half
  616. xchg dx,cx
  617. xchg ax,dx ;cx->ax, ax->dx, dx->cx
  618. mul bx ;multiply high half
  619. add ax,cx ;combine overlapping products
  620. adc dx,0
  621. xchg ax,dx ;ax:dx=time*59659
  622. mov bx,5
  623. div bl ;divide high half by 5
  624. mov cl,al
  625. mov ch,0
  626. mov al,ah ;remainder of divide-by-5
  627. cbw
  628. xchg ax,dx ;use it to extend low half
  629. div bx ;divde low half by 5
  630. mov dx,ax
  631. ; cx:dx is now number of ticks in time
  632. ret
  633. time_to_ticks endp
  634. ENDIF
  635. Bios_Code ends
  636. ENDIF
  637. END