www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1995/04/01/13:02:50

Date: Sat, 1 Apr 1995 11:56:18 -0500
From: John Wilson <wilson AT tats DOT wizvax DOT net>
To: jwvm AT umdsun2 DOT umd DOT umich DOT edu
Subject: Re: Code for controlling PC Timer
Cc: djgpp AT sun DOT soe DOT clarkson DOT edu

>I recall several discussions regarding code for speeding up the PC timer
>so that interrupts could occur at a much faster rate but the time-of-day
>ISR would still be serviced properly. However, this code did not seem to
>be on SimTel and was not mentioned in the new expanded FAQ. Does anyone
>know where this code can be found?

[I'm not on the list, your msg was forwarded to me by Paul Koning]

I've written code to do this for a simulator I'm working on, which simulates
a machine that has 50/60 Hz clock interrupts.  What you do is go ahead and
set timer 0 for your own rate, but then maintain a counter of the number
of clocks since the last BIOS clock tick.  On each interrupt, you add the
number of clocks since the last interrupt (i.e. the divisor that you set to
get your rate) to this counter, and every time the counter wraps past 65536
you call the BIOS ISR.  This way there's a little jitter in the BIOS ticks,
but no cumulative error so the DOS clock is still OK when you exit.

I hacked my code out of the program and included it below.  It's for real
mode but should be easy to convert.

John Wilson

--------------------------------
From Ersatz-11 V1.1 BETA:

; Sample divisors for 50 and 60 Hz
hz50=	23864d	;50 Hz timer divisor =14318180./(12.*50.)
hz60=	19886d	;60 Hz timer divisor =14318180./(12.*60.)
timer_low=word ptr 046Ch	;low word of system BIOS time

; sample call to set up faster ints:
	mov	cx,hz60		;divisor for 60 Hz
	mov	ax,cs		;point at our ISR
	mov	dx,offset clkisr
	mov	di,offset dat:clkold ;dword buf for current vector
	call	clkset		;go set up the clock
[...]

; sample call to restore things before exiting:
	xor	cx,cx		;divisor=0 for usual 18.2 Hz rate
	mov	dx,ds:clkold	;get old ISR address
	mov	ax,ds:clkold+2
	mov	di,offset dat:clkold ;go ahead and overwrite it, we're exiting
	call	clkset		;restore clock
[...]

;+
;
; Set/restore clock ISR.
;
; cx	divisor
;	0 for regular PC rate (1/18.2 sec)
;	HZ60 for 60 Hz rate
;	HZ50 for 50 Hz rate
; ax:dx	ptr to timer ISR
; ds:di	ptr to dword buf for old vector
;
;-
clkset:	push	ds		;save
	push	ax		;save seg of ISR
	mov	ax,3508h	;func=get INT 08h vector
	int	21h
	mov	ds:[di],bx	;save
	mov	ds:[di+2],es
	; wait for leading edge of a BIOS clock tick
	; (so we don't screw up the PC's time of day too much)
	xor	bx,bx		;load 0
	mov	es,bx		;into es
	mov	bx,timer_low	;low word of BIOS clock
	mov	ax,es:[bx]	;get it
@@1:	cmp	ax,es:[bx]	;has it changed?
	je	@@1		;spin until it does (up to 1/18.2 sec)
	cli			;ints off
	mov	al,36h		;;timer 0, lsb/msb
	out	43h,al
	mov	al,cl		;;LSB
	out	40h,al
	mov	al,ch		;;MSB
	out	40h,al
	mov	ds:clkcnt,0	;;init simulated timer #0 counter
	sti			;;(ints back on after next inst)
	mov	ds:clkinc,cx	;;set # clock counts per tick
	pop	ds		;catch seg addr of ISR
	mov	ax,2508h	;func=set INT 08h vector
	int	21h		;to ds:dx
	pop	ds		;catch original ds
	ret
;+
;
; 60 Hz clock ISR.
;
; This routine keeps track of number of clocks the timer chip has counted, and
; calls the BIOS timer during the 60 Hz tick at or after each time the BIOS
; timer would have overflowed.  So BIOS doesn't get its interrupts at exactly
; even intervals but there's no cumulative error, so the DOS/BIOS time-of-day
; clock will be correct when we exit.
;
;-
	public	clkisr
clkisr:	push	ax		;;save
	push	ds
	mov	ax,seg dat	;;establish addressability
	mov	ds,ax
;;; do whatever processing we need at our higher tick rate

	; see if it's time for a BIOS clock tick
	mov	ax,ds:clkinc	;;get # cycles to increment by
	add	ds:clkcnt,ax	;;bump clock, see if 1/18.2 sec has passed
	jc	@@4		;;yes (happens every 65536 counts)
	mov	al,20h		;;generic EOI cmd
	out	20h,al		;;send to 8259A
	pop	ds		;;restore
	pop	ax
	iret
@@4:	; BIOS 54ms tick
	pushf			;;simulate INT instruction
	call	dword ptr ds:clkold ;;chain old handler, send EOI cmd to 8259A
	pop	ds		;;restore
	pop	ax
	iret			;;(restore int enable flag)

; in data segment:
clkcnt	dw	1 dup(?)	;simulated timer #0 counter (BIOS int on carry)
clkinc	dw	1 dup(?)	;# of counts to add to above for each tick
clkold	dw	2 dup(?)	;FAR ptr to old clock ISR

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019