Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/amiga Reverted the CIA-timer based delay() to the p...



details:   https://anonhg.NetBSD.org/src/rev/a005bd5d92d1
branches:  trunk
changeset: 749899:a005bd5d92d1
user:      phx <phx%NetBSD.org@localhost>
date:      Sat Dec 12 13:10:36 2009 +0000

description:
Reverted the CIA-timer based delay() to the pre-5.0 method of a calibrated
delay loop.
This fixes keyboard handshaking problems with some A1200 models since 5.0
and restores the precision for short delays on DraCo systems (the QuickLogic
timer has only a seventh of the CIA precision).
Changed the keyboard handshaking delay from 2000 back to 200ms, although
even the recommended 85ms were successfully tested on the most problematic
A1200 keyboards.
All those changes were tested on an A3000 and A1200 with 68060/50 CPU, and
previously discussed on the port-amiga ML.

diffstat:

 sys/arch/amiga/amiga/amiga_init.c |   20 +++-
 sys/arch/amiga/amiga/locore.s     |   18 ++-
 sys/arch/amiga/dev/clock.c        |  210 +++++++++++++++++++------------------
 sys/arch/amiga/dev/kbd.c          |    8 +-
 4 files changed, 148 insertions(+), 108 deletions(-)

diffs (truncated from 435 to 300 lines):

diff -r 4fa68e7b790b -r a005bd5d92d1 sys/arch/amiga/amiga/amiga_init.c
--- a/sys/arch/amiga/amiga/amiga_init.c Sat Dec 12 12:23:29 2009 +0000
+++ b/sys/arch/amiga/amiga/amiga_init.c Sat Dec 12 13:10:36 2009 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: amiga_init.c,v 1.117 2009/12/11 22:23:08 tsutsui Exp $ */
+/*     $NetBSD: amiga_init.c,v 1.118 2009/12/12 13:10:36 phx Exp $     */
 
 /*
  * Copyright (c) 1994 Michael L. Hitch
@@ -36,7 +36,7 @@
 #include "opt_devreload.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: amiga_init.c,v 1.117 2009/12/11 22:23:08 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: amiga_init.c,v 1.118 2009/12/12 13:10:36 phx Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -765,6 +765,7 @@
 void
 start_c_finish(void)
 {
+       extern u_int32_t delaydivisor;
 #ifdef P5PPC68KBOARD
         struct cfdev *cdp, *ecdp;
 #endif
@@ -895,6 +896,21 @@
                        }
         }
 #endif
+       /*
+        * preliminary delay divisor value
+        */
+
+       if (machineid & AMIGA_68060)
+               delaydivisor = (1024 * 1) / 80; /* 80 MHz 68060 w. BTC */
+
+       else if (machineid & AMIGA_68040)
+               delaydivisor = (1024 * 3) / 40; /* 40 MHz 68040 */
+
+       else if (machineid & AMIGA_68030)
+               delaydivisor = (1024 * 8) / 50; /* 50 MHz 68030 */
+
+       else
+               delaydivisor = (1024 * 8) / 33; /* 33 MHz 68020 */
 }
 
 void
diff -r 4fa68e7b790b -r a005bd5d92d1 sys/arch/amiga/amiga/locore.s
--- a/sys/arch/amiga/amiga/locore.s     Sat Dec 12 12:23:29 2009 +0000
+++ b/sys/arch/amiga/amiga/locore.s     Sat Dec 12 13:10:36 2009 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: locore.s,v 1.148 2009/12/04 17:28:54 tsutsui Exp $     */
+/*     $NetBSD: locore.s,v 1.149 2009/12/12 13:10:36 phx Exp $ */
 
 /*
  * Copyright (c) 1980, 1990 The Regents of the University of California.
@@ -1573,6 +1573,16 @@
        .align 2
 #endif
        nop
+ENTRY_NOPROFILE(delay)
+ENTRY_NOPROFILE(DELAY)
+       movql #10,%d1           | 2 +2
+       movl %sp@(4),%d0        | 4 +4
+       lsll %d1,%d0            | 8 +2
+       movl _C_LABEL(delaydivisor),%d1 | A +6
+Ldelay:                                | longword aligned again.
+       subl %d1,%d0
+       jcc Ldelay
+       rts
 
 #ifdef M68060
 ENTRY_NOPROFILE(intemu60)
@@ -1603,7 +1613,11 @@
        .long   FPU_NONE
 GLOBAL(protorp)
        .long   0x80000002,0    | prototype root pointer
-
+GLOBAL(delaydivisor)
+       .long   12              | should be enough for 80 MHz 68060
+                               | will be adapted to other CPUs in
+                               | start_c_cleanup and calibrated
+                               | at clock attach time.
 #ifdef DEBUG
 ASGLOBAL(fulltflush)
        .long   0
diff -r 4fa68e7b790b -r a005bd5d92d1 sys/arch/amiga/dev/clock.c
--- a/sys/arch/amiga/dev/clock.c        Sat Dec 12 12:23:29 2009 +0000
+++ b/sys/arch/amiga/dev/clock.c        Sat Dec 12 13:10:36 2009 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: clock.c,v 1.50 2009/09/11 19:43:08 phx Exp $ */
+/*     $NetBSD: clock.c,v 1.51 2009/12/12 13:10:36 phx Exp $ */
 
 /*
  * Copyright (c) 1982, 1990 The Regents of the University of California.
@@ -77,7 +77,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.50 2009/09/11 19:43:08 phx Exp $");
+__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.51 2009/12/12 13:10:36 phx Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -100,26 +100,6 @@
 #include <sys/PROF.h>
 #endif
 
-/* the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz.
-   We're using a 100 Hz clock. */
-int amiga_clk_interval;
-int eclockfreq;
-unsigned int fast_delay_limit;
-struct CIA *clockcia;
-
-static u_int clk_getcounter(struct timecounter *);
-
-static struct timecounter clk_timecounter = {
-       clk_getcounter, /* get_timecount */
-       0,              /* no poll_pps */
-       ~0u,            /* counter_mask */
-       0,              /* frequency */
-       "clock",        /* name, overriden later */
-       100,            /* quality */
-       NULL,           /* prev */
-       NULL,           /* next */
-};
-
 /*
  * Machine-dependent clock routines.
  *
@@ -140,6 +120,26 @@
 int clockmatch(struct device *, struct cfdata *, void *);
 void clockattach(struct device *, struct device *, void *);
 void cpu_initclocks(void);
+static void calibrate_delay(struct device *);
+
+/* the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz.
+   We're using a 100 Hz clock. */
+int amiga_clk_interval;
+int eclockfreq;
+struct CIA *clockcia;
+
+static u_int clk_getcounter(struct timecounter *);
+
+static struct timecounter clk_timecounter = {
+       clk_getcounter, /* get_timecount */
+       0,              /* no poll_pps */
+       ~0u,            /* counter_mask */
+       0,              /* frequency */
+       "clock",        /* name, overriden later */
+       100,            /* quality */
+       NULL,           /* prev */
+       NULL,           /* next */
+};
 
 CFATTACH_DECL(clock, sizeof(struct device),
     clockmatch, clockattach, NULL, NULL);
@@ -160,21 +160,20 @@
 {
        const char *clockchip;
        unsigned short interval;
+       int chipfreq;
 #ifdef DRACO
        u_char dracorev;
 #endif
 
-#ifdef DRACO
-       dracorev = is_draco();
-#endif
-
        if (eclockfreq == 0)
                eclockfreq = 715909;    /* guess NTSC */
 
+       chipfreq = eclockfreq;
+
 #ifdef DRACO
+       dracorev = is_draco();
        if (dracorev >= 4) {
-               if (amiga_clk_interval == 0)    /* Only do this 1st time */
-                       eclockfreq /= 7;
+               chipfreq = eclockfreq / 7;
                clockchip = "QuickLogic";
        } else if (dracorev) {
                clockcia = (struct CIA *)CIAAbase;
@@ -186,16 +185,14 @@
                clockchip = "CIA B";
        }
 
-       amiga_clk_interval = (eclockfreq / hz);
-
-       clk_timecounter.tc_name = clockchip;
-       clk_timecounter.tc_frequency = eclockfreq;
-
-       fast_delay_limit = UINT_MAX / amiga_clk_interval;
+       amiga_clk_interval = chipfreq / hz;
 
        if (dp != NULL) {       /* real autoconfig? */
                printf(": %s system hz %d hardware hz %d\n", clockchip, hz,
-                   eclockfreq);
+                   chipfreq);
+
+               clk_timecounter.tc_name = clockchip;
+               clk_timecounter.tc_frequency = chipfreq;
                tc_init(&clk_timecounter);
        }
 
@@ -209,6 +206,8 @@
                draco_ioct->io_timerlo = amiga_clk_interval & 0xff;
                draco_ioct->io_timerhi = amiga_clk_interval >> 8;
 
+               calibrate_delay(dp);
+
                return;
        }
 #endif
@@ -222,7 +221,6 @@
        /*
         * load interval into registers.
          * the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz
-        * supprort for PAL WHEN?!?! XXX
         */
        interval = amiga_clk_interval - 1;
 
@@ -235,6 +233,8 @@
         * start timer A in continuous mode
         */
        clockcia->cra = (clockcia->cra & 0xc0) | 1;
+
+       calibrate_delay(dp);
 }
 
 void
@@ -280,7 +280,7 @@
 }
 
 /*
- * Returns ticks  since last recorded clock "tick"
+ * Returns ticks since last recorded clock "tick"
  * (i.e. clock interrupt).
  */
 static u_int
@@ -326,30 +326,88 @@
 static u_int
 clk_getcounter(struct timecounter *tc)
 {
-       static int last_hardclock_ticks;
-       static u_int last_clock_tick = 0;
-       int old_hardclock_ticks;
-       u_int clock_tick;
+       static int prev_hardclock;
+       static u_int prev_counter;
+       int cur_hardclock;
+       u_int counter;
 
        do {
-               old_hardclock_ticks = hardclock_ticks;
-               clock_tick = clk_gettick();
-       } while (old_hardclock_ticks != hardclock_ticks);
+               cur_hardclock = hardclock_ticks;
+               counter = clk_gettick();
+       } while (cur_hardclock != hardclock_ticks);
 
        /*
         * Handle the situation of a wrapped interval counter, while
         * the hardclock() interrupt was not yet executed to update
         * hardclock_ticks.
         */
-       if (last_hardclock_ticks > old_hardclock_ticks)
-               old_hardclock_ticks = last_hardclock_ticks;
-       if (clock_tick < last_clock_tick &&
-           old_hardclock_ticks == last_hardclock_ticks)
-               old_hardclock_ticks++;
-       last_hardclock_ticks = old_hardclock_ticks;
-       last_clock_tick = clock_tick;
+       if (cur_hardclock < prev_hardclock)
+               cur_hardclock = prev_hardclock;
+       if (counter < prev_counter && cur_hardclock == prev_hardclock)
+               cur_hardclock++;
+
+       prev_hardclock = cur_hardclock;
+       prev_counter = counter;
+
+       return cur_hardclock * amiga_clk_interval + counter;
+}
+
+/*
+ * Calibrate delay loop.
+ * We use two iterations because we don't have enough bits to do a factor of
+ * 8 with better than 1%.
+ *
+ * XXX Note that we MUST stay below 1 tick if using clk_gettick(), even for
+ * underestimated values of delaydivisor.
+ *
+ * XXX the "ns" below is only correct for a shift of 10 bits, and even then
+ * off by 2.4%
+ */
+static void
+calibrate_delay(struct device *dp)



Home | Main Index | Thread Index | Old Index