New self-calibrating spin-wait delay() from Scott Reynolds <scottr@edsi.org>.
authorbriggs <briggs@openbsd.org>
Sun, 4 Feb 1996 16:40:12 +0000 (16:40 +0000)
committerbriggs <briggs@openbsd.org>
Sun, 4 Feb 1996 16:40:12 +0000 (16:40 +0000)
sys/arch/mac68k/mac68k/clock.c
sys/arch/mac68k/mac68k/locore.s
sys/arch/mac68k/mac68k/machdep.c
sys/arch/mac68k/mac68k/via.c
sys/arch/mac68k/mac68k/via.h

index a24b355..154306f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: clock.c,v 1.17 1996/01/29 04:10:00 briggs Exp $        */
+/*     $NetBSD: clock.c,v 1.19 1996/02/03 22:49:58 briggs Exp $        */
 
 /*
  * Copyright (c) 1988 University of Utah.
  */
 
 #if !defined(STANDALONE)
-#include "param.h"
-#include "kernel.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
 
-#include "machine/psl.h"
-#include "machine/cpu.h"
+#include <machine/psl.h>
+#include <machine/cpu.h>
 
 #if defined(GPROF) && defined(PROFTIMER)
-#include "sys/gprof.h"
+#include <sys/gprof.h>
 #endif
 
 #else                          /* STANDALONE */
@@ -407,38 +407,108 @@ resettodr(void)
  */
 #define        CLK_RATE        12766
 
+#define        DELAY_CALIBRATE (0xffffff << 7) /* Large value for calibration */
+#define        LARGE_DELAY     0x40000         /* About 335 msec */
+
+int delay_factor = DELAY_CALIBRATE;
+volatile int delay_flag = 1;
+
 /*
  * delay(usec)
- *     Delay usec microseconds.  This is inaccurate because it
- * assumes that it takes no time to actually execute.  We should
- * try to compensate for this sometime because access to the via
- * is hardly cheap.
+ *     Delay usec microseconds.
  *
- * It would probably be worthwhile to invent a version of this that
- * didn't depend on the VIA.
+ * The delay_factor is scaled up by a factor of 128 to avoid loss
+ * of precision for small delays.  As a result of this, note that
+ * delays larger that LARGE_DELAY will be up to 128 usec too short,
+ * due to adjustments for calculations involving 32 bit values.
  */
 void
 delay(int usec)
 {
-       register int    ticks, t;
+       register unsigned int cycles;
+
+       if (usec > LARGE_DELAY)
+               cycles = (usec >> 7) * delay_factor;
+       else
+               cycles = ((usec > 0 ? usec : 1) * delay_factor) >> 7;
 
-       if (usec <= 0)
-               usec = 1;
+       while ((cycles-- > 0) && delay_flag)
+               ;
+}
+
+/*
+ * Dummy delay calibration.  Functionally identical to delay(), but
+ * returns the number of times through the loop.
+ */
+static int
+dummy_delay(usec)
+       int usec;
+{
+       register unsigned int cycles;
 
-       if (usec < 200000)
-               ticks = (usec * 10000) / CLK_RATE;
+       if (usec > LARGE_DELAY)
+               cycles = (usec >> 7) * delay_factor;
        else
-               ticks = (usec / CLK_RATE) * 10000;
+               cycles = ((usec > 0 ? usec : 1) * delay_factor) >> 7;
 
-       while (ticks) {
-               t = min(ticks, 65535);
+       while ((cycles-- > 0) && delay_flag)
+               ;
+
+       return ((delay_factor >> 7) - cycles);
+}
+
+static void
+delay_timer1_irq()
+{
+       delay_flag = 0;
+}
 
-               via_reg(VIA1, vT2C) = (t & 0xff);
-               via_reg(VIA1, vT2CH) = ((t >> 8) & 0xff);
+/*
+ * Calibrate delay_factor with VIA1 timer T1.
+ */
+void
+mac68k_calibrate_delay()
+{
+       int n;
+       int sum;
 
-               while (!(via_reg(VIA1, vIFR) & V1IF_T2))
-                       ;
+       mac68k_register_via1_t1_irq(delay_timer1_irq);
+       via_reg(VIA1, vIER) = 0x80 | V1IF_T1;
 
-               ticks -= t;
+       for (sum = 0, n = 8; n > 0; n--) {
+               delay_flag = 1;
+               via_reg(VIA1, vT1C) = 0;        /* 1024 clock ticks */
+               via_reg(VIA1, vT1CH) = 4;       /* (approx 1.3 msec) */
+               sum += dummy_delay(1);
        }
+
+       via_reg(VIA1, vIER) = V1IF_T1;
+       via_reg(VIA1, vT1C) = 0;
+       via_reg(VIA1, vT1CH) = 0;
+       mac68k_register_via1_t1_irq(NULL);
+
+       /*
+        * If this weren't integer math, the following would look
+        * a lot prettier.  It should really be something like
+        * this:
+        *      delay_factor = ((sum / 8) / (1024 * 1.2766)) * 128;
+        * That is, average the sum, divide by the number of usec,
+        * and multiply by a scale factor of 128.
+        * 
+        * We can accomplish the same thing by simplifying and using
+        * shifts, being careful to avoid as much loss of precision
+        * as possible.  (If the sum exceeds (2^31-1)/10000, we need
+        * to rearrange the calculation slightly to do this.)
+        */
+       if (sum > 214748)       /* This is a _fast_ machine! */
+               delay_factor = (((sum >> 3) * 10000) / CLK_RATE) >> 3;
+       else
+               delay_factor = (((sum * 10000) >> 3) / CLK_RATE) >> 3;
+
+       /* Reset the delay_flag for normal use */
+       delay_flag = 1;
+
+#ifdef DEBUG
+       printf("delay calibrated, factor = %d\n", delay_factor);
+#endif
 }
index fab0ace..c147b4d 100644 (file)
@@ -820,6 +820,7 @@ start:
 
        .globl  _initenv, _getenvvars   | in machdep.c
        .globl  _setmachdep             | in machdep.c
+       .globl  _VIA_initialize         | in via.c
 
        /* Initialize source/destination control registers for movs */
        moveq   #FC_USERD,d0            | user space
@@ -834,6 +835,7 @@ start:
        jbsr    _getenvvars             | Parse the environment buffer
 
        jbsr    _setmachdep             | Set some machine-dep stuff
+       jbsr    _VIA_initialize         | Initialize the VIAs
 
        jbsr    _vm_set_page_size       | Set the vm system page size, now.
        jbsr    _consinit               | XXX Should only be if graybar on
@@ -2106,3 +2108,10 @@ _mac68k_vrsrc_vec:
        .word   0, 0, 0, 0, 0, 0
 _mac68k_buserr_addr:
        .long   0
+       .globl  _SONICSPACE, _SONICSPACE_size
+_SONICSPACE:
+       .space  108123
+/* size is figured out in if_sn.c.
+   This should be dynamically allocated at some point. */
+_SONICSPACE_size:
+       .long   108123
index 18a799c..22245d3 100644 (file)
@@ -221,6 +221,8 @@ consinit(void)
                ddb_init();
 #endif
                init = 1;
+       } else {
+               mac68k_calibrate_delay();
        }
 }
 
index 81810f7..35abdf1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: via.c,v 1.34 1995/09/28 04:11:18 briggs Exp $  */
+/*     $NetBSD: via.c,v 1.36 1996/02/03 22:50:19 briggs Exp $  */
 
 /*-
  * Copyright (C) 1993  Allen K. Briggs, Chris P. Caputo,
@@ -102,9 +102,6 @@ void        *slotptab[6];
 void
 VIA_initialize()
 {
-       /* Sanity. */
-       if(via_inited){printf("WARNING: Initializing VIA's again.\n");return;}
-
        /* Initialize VIA1 */
        /* set all timers to 0 */
        via_reg(VIA1, vT1L) = 0;
@@ -117,7 +114,6 @@ VIA_initialize()
        /* turn off timer latch */
        via_reg(VIA1, vACR) &= 0x3f;
 
-       Via2Base = Via1Base + VIA2 * 0x2000;
        if (VIA2 == VIA2OFF) {
                /* Initialize VIA2 */
                via2_reg(vT1L) = 0;
@@ -383,3 +379,13 @@ mac68k_register_scsi_irq(irq_func, client_data)
                via2iarg[3] = (void *) 3;
        }
 }
+
+extern void
+mac68k_register_via1_t1_irq(irq_func)
+       void    (*irq_func)(void *);
+{
+       if (irq_func)
+               via1itab[6] = irq_func;
+       else
+               via1itab[6] = rtclock_intr;
+}
index 923eaed..b6b63aa 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: via.h,v 1.14 1995/09/04 05:06:00 briggs Exp $  */
+/*     $NetBSD: via.h,v 1.15 1996/02/03 22:50:22 briggs Exp $  */
 
 /*-
  * Copyright (C) 1993  Allen K. Briggs, Chris P. Caputo,
@@ -177,6 +177,7 @@ int         rbv_vidstatus    (void);
 int            add_nubus_intr   (int addr, void (*func)(), void *client_data);
 void           mac68k_register_scsi_irq(void (*irq_func)(void *), void *clnt);
 void           mac68k_register_scsi_drq(void (*drq_func)(void *), void *clnt);
+void           mac68k_register_via1_t1_irq(void (*irq_func)(void *));
 
 extern void    (*via1itab[7])();
 extern void    (*via2itab[7])();