From: ervin@pinbot.enet.dec.com (Joseph James Ervin)
Subject: Re: Clock speed address
Keywords: clock speed ml
Reply-To: ervin@pinbot.enet.dec.com (Joseph James Ervin)
Organization: Digital Equipment Corporation
Date: Mon, 28 Sep 1992 11:03:25 GMT


Oops...I forgot to include the BEEP dissassembly in my 
last followup to this thread.

Sorry folks.  Here it is now.

>>>Joe Ervin
***********************************************************

1A5C4: ; *** BEEP (XLIB 2 52) ***
1A5C4: 02D9D ! Program
1A5C9: 18EDF ; Save current command, verify DEPTH >= 2 and check args.
1A5CE: 04099 ; <11h>
1A5D3: 1415A ; Internal BEEP (2:Real Number,1:Real Number)
1A5D8: 0312B ! End Marker



1415A: 02D9D ! Program
1415F: 02DCC ! Code
14164: 00035 ! 53 nibbles (next RPL at 14199)
14169: 8FADF92    GOSBVL 29FDA  ; MC: pop stk1(Real Number)to A.W, save regs
14170: 32994      LCHEX  499
14175: 9B621      ?A>C   X      ; Check for excessively large exponent.
                  GOYES  1418A  ; Branch of exponent leq 499.
1417A: 306        LCHEX  6      ; 
1417D: 98A50      ?C>=A  P
                  GOYES  14185
14182: A8E        ACEX   P
14185: 958A0      ?A=0   M
GOYES  14192
1418A: 32300      LCHEX  003            ; Multiply by 1000 to make time
                                        ; value into milliseconds.
1418F: A3A        A=A+C  X
14192: 8DD32A2    GOVLNG 2A23D          ; MC: push A.W as Real Number, restore 
                                        ; regs and continue RPL
 . . . . . ! End of Code
14199: 62E7B ; Internal R->SB and SWAP (1:Real Number)
1419E: 18CEA ; Internal R->SB (1:Real Number)
141A3: 141B2 ; Internal BEEP (System Binary) (2:msec,1:Hz)
141A8: 4241B
141AD: 0312B ! End Marker


141B2: ; *** Internal BEEP (System Binary) (2:msec,1:Hz) ***
141B2: 141B7 ! Machine Code at 141B7
141B7: 8F14660    GOSBVL 06641          ; MC: pop stk1 (System Binary) into A.A
141BE: D6         C=A    A              ; This is the frequency in Hz.
141C0: 06         RSTK=C
141C2: 8F14660    GOSBVL 06641          ; MC: pop stk1 (System Binary) into A.A
                                        ; This is the duration in msecs.
141C9: 7110       GOSUB  141DE          ; MC XFER: save D0,D1,B,D (uses C,D0), 
                                        ; clear carry
141CD: 07         C=RSTK		; Get the Hz from the stack.
141CF: D7         D=C    A		; D = Hz.
141D1: D6         C=A    A		; C = msec.
141D3: 8F6A710    GOSBVL 017A6          ; MC: beep (C=msec,D=Hz)
141DA: 6820       GOTO   14203          ; MC XFER: restore D,B,D1,D0 (C=D0), 
                                        ; clear carry and continue RPL


017A6: ; *** MC: beep (C=msec,D=Hz) ***
017A6: 1B2D607    D0=HEX 706D2          ; RPL System Flags -53 thru -56
017AD: 14A        A=DAT0 B
017B0: 8087300    ?ABIT=1 3             ; Error Beep suppressed?
                  RTNYES
017B7: 8AB00      ?D=0   A              ; frequency = 0?
                  RTNYES		; If yes then just return.
017BC: D5         B=C    A              ; Save time in B.
017BE: AF2        C=0    W
017C1: D9         C=B    A              ; Zero out upper nibbles of time...
017C3: 109        R1=C                  ; and save resulting word in r1.
017C6: DB         C=D    A		; Copy the Hz into C.
017C8: 1B6D407    D0=HEX 704D6          ; CSPEED.  This reflects 
					; the speed of the CPU in 16 Hz units.
					; This is needed since the BEEP code
					; is software timed. 
017CF: AF0        A=0    W
017D2: 142        A=DAT0 A		; Read the CSPEED word.  Reading this
					; via the memory scanner reveals a 
					; value of 1744000/16.
017D5: BF0        ASL    W
017D8: 102        R2=A			; Multiply by 16 to get the actual
					; cycles/second and save in R2. The 
					; resulting number is 1.744 Mhz.  This
					; reflects the effective cycles/second
					; of the CPU after taking the overhead
					; of the display controller.
017DB: A7A        A=A+C  W		; Add in the BEEP Hz.  This is done
					; prevent the accumulation of error
					; due to discarded remainder from the
					; upcoming integer divide.
017DE: A76        C=C+C  W		; And double the Hz value.  This 
					; makes some sense since we need to 
					; toggle the speaker at 2x the 
					; frequency.
017E1: 8F70856    GOSBVL 65807		; A = A/C.  This results in 
;     (cpu cycles/sec)     (beep cyc/sec)
;     ---------------- +  ---------------
;      halfwaves/sec      halfwaves/sec

; Note that the second term simply increases the result of the integer 
; divide by 0.5 on the average.  This keeps the loss of the remainder from
; introducing excessive error into the calculations.  This technique is used
; frequently when an integer divide is performed (see below).

; This gives us a measure of CPU cycles/halfwave.  This tells us how much 
; time we have to use in the overall loop between toggles of the speaker.  
; The result is returned in A.
017E8: AF2        C=0    W		; 
017EB: 20         P=     0
017ED: 3106       LCHEX  60		; = 96 decimal.
017F1: B7A        A=A-C  W		; Subtract #60 from the number of
					; cycles to use up per halfwave. This
					; corresponds to the fixed amount of 
					; time used up in the inner loop.
017F4: 550        GONC   017FA		; Was the cycles/halfwave smaller
					; than #60?  If not, then skip down
					; to 17FA.
017F7: AF0        A=0    W		; (can't have negative value here, 
					; so zero it out.)
017FA: 3141       LCHEX  14		; Else, divide the resulting 
					; cycles/halfwave by 20 decimal.  This
					; is likely because the inner null
					; loop takes around 20 cycles to 
					; execute.  
017FE: 8F70856    GOSBVL 65807		; Integer Divide (a=a/c). A = the 
					; number of iterations of the idle
					; loop required to give the outer
					; loop the desired period.  Note that
					; the accuracy technique of adding in 
					; 1/2 was not necessary since the 
					; divisor was so small compared to the 
					; dividend. 
01805: AF2        C=0    W
01808: A3E        C=C-1  X		; C.x = #FFF.
0180B: 9FA50      ?C>=A  W		; Is resulting idle loop counter less 
					; than FFF?
                  GOYES  01813		; If yes, then skip down to 1813.
01810: AFA        A=C    W		; Else use #FFF as the idle loop cntr.
					; This prevents us from trying to 
					; generate frequencies too low to
					; hear. 
01813: 103        R3=A			; R3 = idle loop counter.
01816: 112        A=R2			; Fetch the CPU speed from R2.
01819: 119        C=R1			; Fetch the msec from R1.
0181C: 8F4EE35    GOSBVL 53EE4		; Multiply.  This gives the total
					; number of CPU cycles that will 
					; transpire during the beep, but 
					; actually 1000 times too high 
					; because we measured time in 
					; msecs rather than seconds. 
01823: 100        R0=A			; Save the total cycles in R0.
01826: 113        A=R3			; A = Idle loop counter.
01829: AF2        C=0    W
0182C: 3302E4     LCHEX  4E20		; C = 20*1000. This is the number
					; of cycles used in the inner loop
					; multiplied by 1000. We are working a 
					; factor of 1000 larger than reality
					; here because of the use of msecs.  
01832: 8F4EE35    GOSBVL 53EE4		; A = A*C, which equals the number
					; of cycles used up in the idle loop
					; during one tick of the speaker 
					; (x1000).
01839: AF2        C=0    W
0183C: 3401E91    LCHEX  19E10		; C = 106,000 decimal.
01843: A72        C=C+A  W		; Add in the 106 cycles used by the
					; rest of the outer loop.  Again, 
					; this is multiplied by a factor of
					; 1000 to take into consideration the
					; fact that we're working with msecs
					; rather than seconds.
01846: AF7        D=C    W		; Save subtotal in D.  This now equals
					; the total number of cycles used up
					; in one tick of the speaker (x1000).
01849: 81E        CSRB			; Divide by 2.  This is going to be
					; added in before an integer divide
					; for accuracy, as described above. 
0184C: 110        A=R0			; A = total number of cycles for whole
					; beep (x1000).
0184F: A7A        A=A+C  W		; Add half of the divisor to the 
					; dividend before the division to 
					; account for loss of remainder. 
01852: AFB        C=D    W		; C = cycles per tick (x1000)
					; Divide total cycles by cycles per
					; iteration of the outer loop.
01855: 8F70856    GOSBVL 65807		; Integer divide.  This gives
					; the number of iterations of the 
					; outer loop.
0185C: A7C        A=A-1  W		; Decrement the result by 1 since we
					; will go through the loop once more
					; than the loop counter value.
0185F: 550        GONC   01865		; ...or if it was already zero then
01862: AF0        A=0    W		; just preserve the zero.
01865: AF6        C=A    W		; 
01868: AF7        D=C    W		; D = outer loop counter.
0186B: 11B        C=R3			; C = idle loop counter.
0186E: AB5        B=C    X		; B = idle loop counter.
01871: 808F       INTOFF
01875: 1FE2100    D1=HEX 0012E		; Timer1 control.
0187C: 1574       C=DAT1 S		; Read the timer1 control nibble.
01880: D2         C=0    A
01882: 15D0       DAT1=C 1		; Clear timer1 control nibble.  This
					; prevents time1 from generating any
					; interrupts or wakes.  This is 
					; restored at the end of the beep.
01886: 1B97607    D0=HEX 70679		; ATTN flag.  We watch for [on] 
					; presses while the sound is playing.
0188D: 1F3C407    D1=HEX 704C3		; ORghost...just so as not to screw
					; up the OUT register bits used for
					; keyboard scanning.
01894: 1573       C=DAT1 X		; Get the ORghost.
01898: 8089B      CBIT=1 11		; Set the speaker bit ON.
0189D: 80D2       P=C    2		; Save the speaker bit in P.
018A1: 8088B      CBIT=0 11		; Set the speaker bit OFF.  This 
					; ensures that P and C.2 have opposite
					; bit polarities at bit 11.  This is
					; used to toggle the speaker bit
					; between successive iterations of the
					; outer loop, by simply exchanging
					; C.2 with P (at 18BE).
018A6: 6300       GOTO   018AA		; NOP
018AA: 142        A=DAT0 A		; [ON] pressed?
018AD: 8AC81      ?A#0   A
                  GOYES  018C8		; Abort if [ON] has been pressed.
018B2: 801        OUT=C			; Tick the speaker on.
018B5: AB4        A=B    X		; Get null loop counter.
018B8: A3C        A=A-1  X
018BB: 5CF        GONC   018B8		; Two-instruction loop to waste time.
018BE: 80F2       CPEX  2		; Toggle the speaker nibble.
018C2: A7F        D=D-1  W		; Decrement the outer loop count.
018C5: 54E        GONC   018AA
018C8: 1573       C=DAT1 X		; ********* Clean-up and exit *******
018CC: 801        OUT=C			; Toggle the speaker off.
018CF: 1FE2100    D1=HEX 0012E
018D6: 1554       DAT1=C S		; Restore the saved TIME1 control.
018DA: 20         P=     0
018DC: 8080       INTON			; Restore keyboard interrupts.
018E0: 03         RTNCC


Newsgroups: comp.sys.hp48