{$R+,S+,I+,N+,E+} {$IFDEF VER70} {$Q+,G-} {$ENDIF} (* Compiled with TurboPascal 5.00, 7.01 for 8086 without 8087 *) {$M 4096, 0, 0} program INT70AT2 ; (* DEMO of use of programmable interrupt timer in PC-AT - remember also the 8253 at $40. *) (* J R Stockton, www.merlyn.demon.co.uk *) uses Dos, Crt ; const RTCsel = $70 { RTC chip base address in I/O space} ; RTCdat = RTCsel+1 ; RegA = $0A ; RegB = $0B ; RegC = $0C ; AT_int = $70 ; IC1 = $20 { Interrupt Controller Chip 1 base address in I/O space} ; IC2 = $A0 { Interrupt Controller Chip 2 base address in I/O space - AT only} ; PIE = $40 ; var JJ : longint ; procedure PIintHandler{(Flags,cs,ip,ax,bx,cx,dx,si,di,ds,es,bp : word)} ; { Int $70 on PC-AT only; "1024Hz"; 1024*42/43÷1000.186 } interrupt ; const Q : byte = 21 ; EOI = $20 ; var TV : byte ; begin Port[RTCsel] := RegC ; TV := Port[RTCdat] { read polls/clears flags } ; Inc(Q) ; if Q>42 then Q := 0 else Inc(JJ) { Adjust 1024 to nigh 1000 } ; Port[IC2+0] := EOI ; Port[IC1+0] := EOI ; end {PIH} ; { Needs Bit 6 in Reg B of RTC chip to have been set } { Needs 8259(s) to have been enabled on right bit(s) } var SavePIvec, ExitSave : pointer ; XP : byte ; {$F+} procedure PIoff {$F-} ; var xxx: byte; begin Writeln(' PI off') ; Port[RTCsel] := RegB ; xxx := Port[RTCdat]; Port[RTCsel] := RegB; Port[RTCdat] := xxx and not PIE ; Port[IC2+1] := XP ; SetIntVec(AT_int, SavePIvec) ; ExitProc := ExitSave ; Write(' ') ; Readln ; end {PIoff} ; const Rate = $26 { not $22 even on T486/33!; $23=8192Hz .. $2F=2Hz } ; procedure PIon { HD146818-type RTC + CMOS RAM does this } ; { Rate $26 = 38 for 1024Hz : MSB is UIP bit : figs on PPC640 : ? first field B6..B4=DV2..DV0 - freq 2=32768; 1=1024; 0,3,4,5=256; 6,7=0 ?? ? second field B3..B0=RS3..RS0 - freqv2^(f-1), 4 OK } const Mask1 = $01 (** See D4:\CFS\DHP\INTERRUP.DOC ; IAR's AnnaBook p.53 **) ; var xxx: byte; begin Writeln(' PI on') ; ExitSave := ExitProc ; ExitProc := @PIoff { Ensure OFF at end } ; GetIntVec(AT_int, SavePIvec) ; SetIntVec(AT_int, @PIintHandler) ; XP := Port[IC2+1] ; Port[IC2+1] := Port[IC2+1] and not Mask1 { Enable } ; Port[RTCsel] := RegA ; Port[RTCdat] := Rate ; Port[RTCsel] := RegB ; xxx := Port[RTCdat]; Port[RTCsel] := RegB; Port[RTCdat] := xxx or PIE ; Port[RTCsel] := RegC ; xxx := Port[RTCdat]; { dummy read access to unlock int } end {PIon} ; var BB : byte ; C : char ; Freq : real ; K, KL : longint ; T : byte absolute $0040:$006C { increments at ~ 18.2Hz } ; BEGIN ; Writeln ; Writeln('INT70-AT.PAS : Expects a PC-AT+') ; Writeln('Hogs Interrupt ', AT_int, '; side-effects are uncertain.') ; Writeln('PC-AT+ only - Int $70 = 112 - seems OK now') ; JJ := 0 ; PIon ; BB := (Rate and $7F) shr 4 ; C := char(Ord('0')+BB) ; case BB of { as observed on PPC640 } 2 : Freq := 32768.0 { Tandon PacII 486/33 : 32768.0 } ; 1 : Freq := 1024.0 { Tandon PacII 486/33 : 0 } ; 0,3,4,5 : Freq := 256.0 { Tandon PacII 486/33 : 0 } ; 6,7 : Freq := 0.0 end ; BB := Rate and $0F ; for KL := 2 to BB do Freq := Freq / 2.0 ; if BB>9 then BB := BB+7 ; Writeln(' Rate = ', Rate, ' = $', C, char(Ord('0')+BB), '; Freq = ', Freq:0:3, 'Hz *42/43;') ; Freq := Freq * 42/43 ; Writeln(' Too much interrupt processing slows Crt.Delay!') ; Write(' CRT.DELAY(1000{ms}) ; : ') ; JJ := 0 ; Delay(1000) ; KL := JJ ; Writeln(KL:7, ', should be about ', Round(Freq)) ; Write(' Using 5s @ 18.2Hz = 91 : ') ; repeat KL := T until (KL<160) and (KL=KL ; KL := JJ ; Writeln(KL:7, ', should be about ', Round(5*Freq)) ; Write(^G) ; END. There was a "FAQ"-posting (now in JRS's file RTC-FAQ) : From: chris@pfsparc02.phil15.uni-sb.de (Christian Blum) Newsgroups: comp.os.msdos.programmer Subject: The Real Time Clock - Answers, not questions :) Date: 7 Feb 1994 20:34:08 GMT Organization: CIP-Pool, Media Centre, University of Saarland at Saarbruecken and it was his E-mail help which finally removed all known errors in my code. JRS.