From: wild@nessie.cs.id.ethz.ch (Markus Wild)
Subject: Re: PAL->NTSC Uhr langsamer???
Organization: Swiss Federal Institute of Technology (ETH), Zurich, CH
Date: Thu, 3 Sep 1992 21:54:05 GMT

In article <1992Sep3.092136.3831@ifi.unizh.ch> blatter@ifi.unizh.ch (Martin A. Blatter) writes:
>In article <BtyKEF.6up@oytix.north.de> mike@oytix.north.de (Mike Fleischer) writes:
>>ich wollte meinen Amiga unter UNIX gerne auf NTSC stellen, da ich einen 
>>A2024 habe und die hoehere Bildwiederholfrequenz angenehmer finde.
>>Das klappte auch tadellos, nur, was mir am nexten Tag unangenehm auffiel,
>>war die Tatsache, dass die Uhr in 24 Stunden ca. 10 Minuten nachlief.
>>Ich habe dabei einfach nur den internen Jumper auf dem Motherboard auf
>>NTSC gestellt, sonst nix. Habe ich was vergessen oder falsch gemacht???
>
>Nein, Du hast nix falsch gemacht. Leider ist das ein Bug im Amiga Unix,
>der zwar bekannt ist, aber nie behoben wurde. Wir haben das auf

Also ich das Problem auf meinem Unix mit einem mittelpraechtigen Hack 
geloest, der nicht ganz unkritisch ist (siehe Kommentar in der Source), aber
die erwaehnte Race-Condition hat bei mir noch nie zugeschlagen. Da der
Source ziemlich klein ist, haenge ich ihn mal an hier:

/*
 * Repair wrong timing set in CIA chip, if running NTSC video on a machine
 * with 50 Hz power frequency.
 *
 * 1.0  91-10-25  M.Wild   first hack
 *
 * Based on /usr/amiga/sys/driver/cl.c. THANKS Commo for providing the 
 * kernel source!
 */

#include <sys/types.h>
#include <sys/param.h>
#include <sys/amiga/amiga.h>
#include <sys/mman.h>
#include <signal.h>
#include <fcntl.h>
#include <stdio.h>

/* param.h has hibyte/lobyte that don't work */
#undef lobyte
#undef hibyte

#define lobyte(x) ((unsigned char)(x))
#define hibyte(x) ((unsigned char)((unsigned)(x)>>8))

volatile unsigned char *custom_chips;

#define ACIAA ((struct acia *) &custom_chips[0xbfe001 - (long)AHWBOT])

/* the following definition copied from /usr/sys/amiga/inc/amigahr.h: */

/*
 * 8520 CIA registers.
 */
struct acia {
        unsigned char   pra;            /* Peripheral data register A   */
        unsigned char   cia0[0xFF];
        unsigned char   prb;            /* Peripheral data register B   */
        unsigned char   cia1[0xFF];
        unsigned char   ddra;           /* Data direction register A    */
        unsigned char   cia2[0xFF];
        unsigned char   ddrb;           /* Data direction register B    */
        unsigned char   cia3[0xFF];
        unsigned char   talo;           /* Timer A low register         */
        unsigned char   cia4[0xFF];
        unsigned char   tahi;           /* Timer A high register        */
        unsigned char   cia5[0xFF];
        unsigned char   tblo;           /* Timer B low register         */
        unsigned char   cia6[0xFF];
        unsigned char   tbhi;           /* Timer B high register        */
        unsigned char   cia7[0xFF];
        unsigned char   todl;           /* Time of day low register     */
        unsigned char   cia8[0xFF];
        unsigned char   todm;           /* Time of day middle register  */
        unsigned char   cia9[0xFF];
        unsigned char   todh;           /* Time of day high register    */
        unsigned char   cia10[0xFF];
        unsigned char   cia11[0x100];
        unsigned char   sdr;            /* Serial data register         */
        unsigned char   cia12[0xFF];
        unsigned char   icr;            /* Interrupt control register   */
        unsigned char   cia13[0xFF];
        unsigned char   cra;            /* Control register A           */
        unsigned char   cia14[0xFF];
        unsigned char   crb;            /* Control register B           */
        unsigned char   cia15[0xFF];
};

/*
 * open /dev/amiga and map the custom chips (incl CIAs) into user-space.
 */
void
map_custom_chips ()
{
  int fd;

  if ((fd = open ("/dev/amiga/", O_RDWR)) < 0)
    {
      perror ("Can't open /dev/amiga");
      exit (1);
    }

  custom_chips = (unsigned char *) mmap (0, AHWLEN, PROT_READ|PROT_WRITE, 
                                         MAP_SHARED, fd, AHWBOT);

  if (custom_chips == (unsigned char *) -1)
    {
      perror ("Can't mmap /dev/amiga");
      exit (1);
    }

  /* we got them ;-)) */
}

#ifdef COMMO
#define EHZ             ((hz == 50)?709379:715909)
#define ATICKS          ((EHZ+HZ/2)/HZ)
#else
/* value determined heuristically by correcting above value.. */
#define EHZ             ((hz == 50)?709290:715909)
#define ATICKS          ((EHZ+HZ/2)/HZ)
#endif

void
main (int argc, char **argv)
{
  int hz;

  if (argc != 2 ||
      ((hz = atoi (argv[1])) != 50 && hz != 60))
    {
      printf ("%s: [50|60]\n", argv[0]);
      exit (1);
    }

  map_custom_chips ();

  /* this is a critical part of code.. the first line stops the clock. As long
   * as the clock is stopped, no task switching will take place, so we're safe
   * for the next instructions, then at last we restart the timer. I guess 
   * there could be a race condition when trying to stop the clock. If we 
   * lose the CPU in exactly this moment, we'll never get it back, and the 
   * system is stalled. */
  ACIAA->cra = 0;               /* stop the timer */
  ACIAA->talo = lobyte(ATICKS);  /* load it with new values */
  ACIAA->tahi = hibyte(ATICKS); 
  ACIAA->cra = 0x11;            /* and restart it */

  exit (0);
}


Es duerfte klar sein, dass dieses Ding nur von privilegierten Usern
ausgefuehrt werden darf (nur schon wegen der Lese-Berechtigung von /dev/amiga).
Ich hab ein /etc/rc2.d/S91clock File, das mir die Korrektur beim booten
vornimmt:

/usr/local/bin/speedy 50

-Markus
-- 
Markus M. Wild    -  wild@nessie.cs.id.ethz.ch  |  wild@amiga.physik.unizh.ch 
Vital papers will demonstrate their vitality by spontaneously moving
from where you left them to where you can't find them.
Newsgroups: de.comp.sys.amiga.misc