From 291d8cbf3ab576e3845ea3d979114d47f6c72993 Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 30 Nov 1995 21:52:46 +0000 Subject: [PATCH] Add kernel option for separate {stat,prof}clock --- sys/arch/atari/atari/locore.s | 22 +++- sys/arch/atari/atari/vectors.s | 6 +- sys/arch/atari/conf/GENERIC | 3 +- sys/arch/atari/dev/clock.c | 188 +++++++++++++++------------------ 4 files changed, 109 insertions(+), 110 deletions(-) diff --git a/sys/arch/atari/atari/locore.s b/sys/arch/atari/atari/locore.s index 192bce2f1642..0a63e2b74754 100644 --- a/sys/arch/atari/atari/locore.s +++ b/sys/arch/atari/atari/locore.s @@ -1,4 +1,4 @@ -/* $NetBSD: locore.s,v 1.10 1995/11/30 00:57:36 jtc Exp $ */ +/* $NetBSD: locore.s,v 1.11 1995/11/30 21:52:46 leo Exp $ */ /* * Copyright (c) 1988 University of Utah. @@ -498,7 +498,6 @@ _spurintr: jra rei /* MFP timer A handler --- System clock --- */ - /* Note: Reduce by factor 4 before handling */ mfp_tima: moveml d0-d1/a0-a1,sp@- | save scratch registers lea sp@(16),a1 | get pointer to PS @@ -509,7 +508,21 @@ mfp_tima: moveml sp@+,d0-d1/a0-a1 | restore scratch regs addql #1,_cnt+V_INTR | chalk up another interrupt jra rei | all done - + +#ifdef STATCLOCK + /* MFP timer C handler --- Stat/Prof clock --- */ +mfp_timc: + moveml d0-d1/a0-a1,sp@- | save scratch registers + lea sp@(16),a1 | get pointer to PS + movl a1,sp@- | push pointer to PS, PC + jbsr _statintr | call statistics clock handler + addql #4,sp | pop params + addql #1,_intrcnt+36 | add another stat clock interrupt + moveml sp@+,d0-d1/a0-a1 | restore scratch regs + addql #1,_cnt+V_INTR | chalk up another interrupt + jra rei | all done +#endif /* STATCLOCK */ + /* MFP ACIA handler --- keyboard/midi --- */ mfp_kbd: addql #1,_intrcnt+8 | add another kbd/mouse interrupt @@ -1947,8 +1960,9 @@ _intrnames: .asciz "5380-DMA" .asciz "nmi" .asciz "8530-SCC" + .asciz "statclock" _eintrnames: .even _intrcnt: - .long 0,0,0,0,0,0,0,0,0 + .long 0,0,0,0,0,0,0,0,0,0 _eintrcnt: diff --git a/sys/arch/atari/atari/vectors.s b/sys/arch/atari/atari/vectors.s index e7b81a13701c..8543bd510f03 100644 --- a/sys/arch/atari/atari/vectors.s +++ b/sys/arch/atari/atari/vectors.s @@ -1,4 +1,4 @@ -/* $NetBSD: vectors.s,v 1.2 1995/05/05 16:30:35 leo Exp $ */ +/* $NetBSD: vectors.s,v 1.3 1995/11/30 21:52:50 leo Exp $ */ /* * Copyright (c) 1988 University of Utah @@ -133,7 +133,11 @@ Lvectab: .long _badmfpint | 66: modem port 1 - CTS .long _badmfpint | 67: unassigned .long _badmfpint | 68: modem port 1 baudgen (Timer D) +#ifdef STATCLOCK + .long mfp_timc | 69: Timer C {stat,prof}clock +#else .long _badmfpint | 69: Timer C +#endif /* STATCLOCK */ .long mfp_kbd | 70: KBD/MIDI IRQ .long mfp_fd_acsi | 71: FDC/ACSI DMA .long _badmfpint | 72: Display enable counter diff --git a/sys/arch/atari/conf/GENERIC b/sys/arch/atari/conf/GENERIC index 9d32164b67b5..fa8d92b6785f 100644 --- a/sys/arch/atari/conf/GENERIC +++ b/sys/arch/atari/conf/GENERIC @@ -1,5 +1,5 @@ # -# $NetBSD: GENERIC,v 1.8 1995/11/30 00:57:49 jtc Exp $ +# $NetBSD: GENERIC,v 1.9 1995/11/30 21:53:07 leo Exp $ # # Generic atari # @@ -90,6 +90,7 @@ options TT_SCSI # SCSI-support for TT options FALCON_SCSI # SCSI-support for Falcon options TT_VIDEO # Graphics support for TT options FALCON_VIDEO # Graphics support for FALCON +options STATCLOCK # Separate {stat,prof}clock # # Build one kernel that can boot from any disk. diff --git a/sys/arch/atari/dev/clock.c b/sys/arch/atari/dev/clock.c index c1471e4dc8d2..d00994f59d88 100644 --- a/sys/arch/atari/dev/clock.c +++ b/sys/arch/atari/dev/clock.c @@ -1,4 +1,4 @@ -/* $NetBSD: clock.c,v 1.4 1995/09/23 20:23:28 leo Exp $ */ +/* $NetBSD: clock.c,v 1.5 1995/11/30 21:53:17 leo Exp $ */ /* * Copyright (c) 1988 University of Utah. @@ -55,21 +55,20 @@ #include #endif +/* + * The MFP clock runs at 2457600Hz. We use a {system,stat,prof}clock divider + * of 200. Therefore the timer runs at an effective rate of: + * 2457600/200 = 12288Hz. + */ +#define CLOCK_HZ 12288 + /* * Machine-dependent clock routines. * - * Startrtclock restarts the real-time clock, which provides - * hardclock interrupts to kern_clock.c. - * * Inittodr initializes the time of day hardware which provides * date functions. * * Resettodr restores the time of day hardware after a time change. - * - * A note on the real-time clock: - * We actually load the clock with CLK_INTERVAL-1 instead of CLK_INTERVAL. - * This is because the counter decrements to zero after N+1 enabled clock - * periods where N is the value loaded into the counter. */ int clockmatch __P((struct device *, struct cfdata *, void *)); @@ -83,7 +82,22 @@ struct cfdriver clockcd = { static u_long gettod __P((void)); static int settod __P((u_long)); -static int divisor; +static int divisor; /* Systemclock divisor */ + +/* + * Statistics and profile clock intervals and variances. Variance must + * be a power of 2. Since this gives us an even number, not an odd number, + * we discard one case and compensate. That is, a variance of 64 would + * give us offsets in [0..63]. Instead, we take offsets in [1..63]. + * This is symetric around the point 32, or statvar/2, and thus averages + * to that value (assuming uniform random numbers). + */ +#ifdef STATCLOCK +static int statvar = 32; /* {stat,prof}clock variance */ +static int statmin; /* statclock divisor - variance/2 */ +static int profmin; /* profclock divisor - variance/2 */ +static int clk2min; /* current, from above choises */ +#endif int clockmatch(pdp, cfp, auxp) @@ -109,13 +123,33 @@ void *auxp; * at an effective rate of: 2457600/200 = 12288Hz. The * following expression works for 48, 64 or 96 hz. */ - divisor = 12288/hz; + divisor = CLOCK_HZ/hz; MFP->mf_tacr = 0; /* Stop timer */ MFP->mf_iera &= ~IA_TIMA; /* Disable timer interrupts */ MFP->mf_tadr = divisor; /* Set divisor */ + if (hz != 48 && hz != 64 && hz != 96) { /* XXX */ + printf (": illegal value %d for systemclock, reset to %d\n\t", + hz, 64); + hz = 64; + } printf(": system hz %d timer-A divisor 200/%d\n", hz, divisor); +#ifdef STATCLOCK + if ((stathz == 0) || (stathz > hz) || (CLOCK_HZ % stathz)) + stathz = hz; + if ((profhz == 0) || (profhz > (hz << 1)) || (CLOCK_HZ % profhz)) + profhz = hz << 1; + + MFP->mf_tcdcr &= 0x7; /* Stop timer */ + MFP->mf_ierb &= ~IB_TIMC; /* Disable timer inter. */ + MFP->mf_tcdr = CLOCK_HZ/stathz; /* Set divisor */ + + statmin = (CLOCK_HZ/stathz) - (statvar >> 1); + profmin = (CLOCK_HZ/profhz) - (statvar >> 1); + clk2min = statmin; +#endif /* STATCLOCK */ + /* * Initialize Timer-B in the ST-MFP. This timer is used by the 'delay' * function below. This time is setup to be continueously counting from @@ -134,13 +168,50 @@ void cpu_initclocks() MFP->mf_ipra &= ~IA_TIMA; /* Clear pending interrupts */ MFP->mf_iera |= IA_TIMA; /* Enable timer interrupts */ MFP->mf_imra |= IA_TIMA; /* ..... */ + +#ifdef STATCLOCK + MFP->mf_tcdcr = (MFP->mf_tcdcr & 0x7) | (T_Q200<<4); /* Start */ + MFP->mf_iprb &= ~IB_TIMC; /* Clear pending interrupts */ + MFP->mf_ierb |= IB_TIMC; /* Enable timer interrupts */ + MFP->mf_imrb |= IB_TIMC; /* ..... */ +#endif /* STATCLOCK */ } -setstatclockrate(hz) - int hz; +setstatclockrate(newhz) + int newhz; { +#ifdef STATCLOCK + if (newhz == stathz) + clk2min = statmin; + else clk2min = profmin; +#endif /* STATCLOCK */ } +#ifdef STATCLOCK +void +statintr(frame) + register struct clockframe *frame; +{ + register int var, r; + + var = statvar - 1; + do { + r = random() & var; + } while(r == 0); + + /* + * Note that we are always lagging behind as the new divisor + * value will not be loaded until the next interrupt. This + * shouldn't disturb the median frequency (I think ;-) ) as + * only the value used when switching frequencies is used + * twice. This shouldn't happen very often. + */ + MFP->mf_tcdr = clk2min + r; + + statclock(frame); +} +#endif /* STATCLOCK */ + /* * Returns number of usec since last recorded clock "tick" * (i.e. clock interrupt). @@ -203,97 +274,6 @@ int n; } } -#ifdef PROFTIMER -/* - * This code allows the amiga kernel to use one of the extra timers on - * the clock chip for profiling, instead of the regular system timer. - * The advantage of this is that the profiling timer can be turned up to - * a higher interrupt rate, giving finer resolution timing. The profclock - * routine is called from the lev6intr in locore, and is a specialized - * routine that calls addupc. The overhead then is far less than if - * hardclock/softclock was called. Further, the context switch code in - * locore has been changed to turn the profile clock on/off when switching - * into/out of a process that is profiling (startprofclock/stopprofclock). - * This reduces the impact of the profiling clock on other users, and might - * possibly increase the accuracy of the profiling. - */ -int profint = PRF_INTERVAL; /* Clock ticks between interrupts */ -int profscale = 0; /* Scale factor from sys clock to prof clock */ -char profon = 0; /* Is profiling clock on? */ - -/* profon values - do not change, locore.s assumes these values */ -#define PRF_NONE 0x00 -#define PRF_USER 0x01 -#define PRF_KERNEL 0x80 - -initprofclock() -{ -#if NCLOCK > 0 - struct proc *p = curproc; /* XXX */ - - /* - * If the high-res timer is running, force profiling off. - * Unfortunately, this gets reflected back to the user not as - * an error but as a lack of results. - */ - if (clockon) { - p->p_stats->p_prof.pr_scale = 0; - return; - } - /* - * Keep track of the number of user processes that are profiling - * by checking the scale value. - * - * XXX: this all assumes that the profiling code is well behaved; - * i.e. profil() is called once per process with pcscale non-zero - * to turn it on, and once with pcscale zero to turn it off. - * Also assumes you don't do any forks or execs. Oh well, there - * is always adb... - */ - if (p->p_stats->p_prof.pr_scale) - profprocs++; - else - profprocs--; -#endif - /* - * The profile interrupt interval must be an even divisor - * of the CLK_INTERVAL so that scaling from a system clock - * tick to a profile clock tick is possible using integer math. - */ - if (profint > CLK_INTERVAL || (CLK_INTERVAL % profint) != 0) - profint = CLK_INTERVAL; - profscale = CLK_INTERVAL / profint; -} - -startprofclock() -{ - unsigned short interval; - - /* stop timer B */ - ciab.crb = ciab.crb & 0xc0; - - /* load interval into registers. - the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz */ - - interval = profint - 1; - - /* order of setting is important ! */ - ciab.tblo = interval & 0xff; - ciab.tbhi = interval >> 8; - - /* enable interrupts for timer B */ - ciab.icr = (1<<7) | (1<<1); - - /* start timer B in continuous shot mode */ - ciab.crb = (ciab.crb & 0xc0) | 1; -} - -stopprofclock() -{ - /* stop timer B */ - ciab.crb = ciab.crb & 0xc0; -} - #ifdef GPROF /* * profclock() is expanded in line in lev6intr() unless profiling kernel.