Subject: A1230 clock and SCSI, hints
To: None <amiga@NetBSD.ORG, de_smet@lurpa.ens-cachan.fr,>
From: DE SMET Olivier <de_smet@lurpa13.ens-cachan.fr>
List: amiga
Date: 03/24/1995 09:28:11
Hello,

Some news about the clock for an A1230 GVP board. Finally I convert
the ASM to the MIT format by hand and make 2 quick C programmes to
use with. The main problem is the fact that the routine is VERY
UNRELIABLE .. I got a bad date for 50% of the call.

Perhaps with this programmes, you could had a new entry for the
clock initialisation in the kernel. To identify the machine correctly,
you should have an A1200 and a board with those references:

er_Manufacturer                 2017
er_Product                        11

Olivier

Here follow the infos from a GVP-Info program about the board:

---

cd_BoardAddress            $00E90000       er_Reserved c-f        $00000488
cd_BoardSize               $00010000       er_Type                %11010001
cd_SlotAddress                   233       da_Config              %00010000
cd_SlotSize                        1       da_Flaags                    $00
cd_Driver                  $0100E240       da_Size                564 bytes
cd_Flags                   %00000000       da_DiagPoint           $000004FE
er_Flags                   %00000000       da_BootPoint           $0000059A
er_Manufacturer                 2017
er_Product                        11
er_SerialNumber            $EEEEEEEE

Driver
        Name        "gvpscsi.device"
        Version                    5
        Revision                   3
--

asm source to read the clock of an A1230 turboII+ accelerator card
for A1200. MIT format.
Hmm I commented out the call for 'Disable' and 'Enable' but I think
this routine should be called without any interruptions enable.

the access to 0x00bfe301 is used to wait a tick for the E clock
(~700Khz) and serve as timing. It's a kind of one wired clock and you
have to do ALL the low level serial protocol.

But I think there are some trouble: with my previous 1230 board (a
40Mhz one without MMU) the reading of the clock was always right. But
when I changed to an 50Mhz one (with MMU), now the reading of the
clock is VERY unstable. I think the change of speed cause some
'drift'in the timing, because I always got the right first bits, but
the last one are false witch cause a bad date of plus or minus one
month.

Another problem is that this clock is wired at adress #0x03008000 and
#0x0300c000. As the board only allow and test fast ram from 0x01000000
up to 0x02ffffff (32Mo), under Amigados, there are no 'serious'
problem to read and write at those adress (except with Enforcer). But
under Linux or NetBSD you must allow such weird acces outside from
I/O range :( The MMU MUST take this into account, and I don't known
enough to do it myself (and not enough time too)

The same problem exist with the DMA mode of the SCSI extension of the
board (A1291). It use also adress around #0x03008000 to write the high
order bits of the DMA adress. So actually you can't use DMA mode on an
SCSI disk :(

(I can send an uuencode image of the gvpscsi.device in rom if it can
help)

If this can help someone to integrate this board, I'll be pleased to
have some news about.

Thanks in advance,

Olivier 

de_smet@lurpa.ens-cachan.fr


--rc1.s--

.text
                      .even
pulse_bit:
                       moveml   d5-d6,sp@-
                       movel    d0,d5
                       bra      bcl1_1
bcl0_1:
                       movel    #0x00bfe301,a0
                       moveb    a0@,d6
                       subql    #1,d5
bcl1_1:
                       tstl     d5
                       bne      bcl0_1
                       moveb    d6,d0
                       moveml   sp@+,d5-d6
                       rts

test_bit:
                       movel    #0x03008000,a0
                       btst     #7,a0@
                       beq      bcl0_2
                       moveql   #1,d0
                       bra      bcl1_2
bcl0_2:
                       moveql   #0,d0
bcl1_2:
                       rts

emit_bit:
                       movel    #0x03008000,a0
                       clrl     a0@
                       tstb     d0
                       beq      bcl0_3
                       moveql   #1,d0
                       bsr      pulse_bit
                       movel    #0x0300c000,a0
                       clrl     a0@
                       moveql   #0x32,d0
                       bsr      pulse_bit
                       bra      bcl1_3
bcl0_3:
                       moveql   #0xc,d0
                       bsr      pulse_bit
                       movel    #0x0300c000,a0
                       clrl     a0@
                       moveql   #0x28,d0
                       bsr      pulse_bit
bcl1_3:
                       rts

synchro_start:
                       movel    #0x0300c000,a0
                       clrl     a0@
                       moveql   #0xa,d0
                       bsr      pulse_bit
                       bsr      test_bit
                       tstw     d0
                       beq      bcl0_4
                       movel    #0x03008000,a0
                       clrl     a0@
                       moveql   #0x64,d0
                       addl     D0,D0
                       bsr      pulse_bit
                       movel    #0x0300c000,a0
                       clrl     a0@
                       moveql   #0x24,d0
                       bsr      pulse_bit
                       bsr      test_bit
                       tstw     d0
                       bne      bcl0_4
                       moveql   #0x78,d0
                       bsr      pulse_bit
                       moveql   #1,d0
                       bra      bcl1_4
bcl0_4:
                       moveql   #0,d0
bcl1_4:
                       rts

emit_code:
                       moveml   d2/d6-d7,sp@-
                       movel    d0,d7
                       moveql   #0,d6
bcl0_5:
                       moveql   #1,d0
                       movel    d0,d1
                       asll     d6,d1
                       moveb    d7,d2
                       andb     d1,d2
                       beq      bcl1_5
                       bsr      emit_bit
                       bra      bcl2_5
bcl1_5:
                       moveql   #0,d0
                       bsr      emit_bit
bcl2_5:
                       addql    #1,d6
                       moveql   #8,d0
                       cmpl     d0,d6
                       blt      bcl0_5
                       moveml   sp@+,d2/d6-d7
                       rts

read_rtc:
                       moveml   d4-d7/a5,sp@-
                       movel    d0,d7
                       movel    a0,a5
                       moveql   #0,d5
                       bra      bcl3_6
bcl0_6:
                       moveql   #0x14,d0
                       bsr      pulse_bit
                       moveql   #0,d6
                       moveql   #0,d4
bcl1_6:
                       bsr      read_bit
                       tstb     d0
                       beq      bcl2_6
                       moveql   #1,d0
                       asll     d4,d0
                       orb      d0,d6
bcl2_6:
                       addql    #1,d4
                       moveql   #8,d0
                       cmpl     d0,d4
                       blt      bcl1_6
                       moveb    d6,a5@(d5)
                       addql    #1,d5
bcl3_6:
                       cmpl     d7,d5
                       blt      bcl0_6
                       moveml   sp@+,d4-d7/a5
                       rts

init_read:
                       bsr      synchro_start
                       tstw     d0
                       beq      bcl0_7
                       moveql   #0x66,d0
                       addl     d0,d0
                       bsr      emit_code
bcl0_7:
                       rts

.globl _read_time
_read_time:
                       subqw    #4,sp
                       moveml   d2-d3/a6,sp@-
;                       movel    4,a6              
;                       jsr      a6@(-0x78)        call for 'Disable' function
                       bsr      init_read
                       moveql   #0x78,d0
                       addl     d0,d0
                       bsr      emit_code
                       moveql   #3,d0
                       bsr      emit_code
                       moveql   #2,d0
                       bsr      emit_code
                       moveql   #4,d0
                       lea      sp@(0xc),a0
                       bsr      read_rtc
;                       jsr      a6@(-0x7e)        call for 'Enable' function
                       moveql   #0,d0
                       moveb    sp@(0xf),d0
                       swapw    d0
                       clrw     d0
                       asll     #8,d0
                       moveql   #0,d1
                       moveb    sp@(0xe),d1
                       swapw    d1
                       clrw     d1
                       moveql   #0,d2
                       moveb    sp@(0xd),d2
                       asll     #8,d2
                       moveql   #0,d3
                       moveb    sp@(0xc),d3
                       orl      d2,d3
                       orl      d1,d3
                       orl      d3,d0
                       moveml   sp@+,d2-d3/a6
                       addqw    #4,sp
                       rts              ; d0 : elapsed seconds since 01/01/78

read_bit:
                       subqw    #4,sp
                       movel    #0x03008000,a0
                       clrl     a0@
                       moveql   #1,d0
                       bsr      pulse_bit
                       movel    #0x0300c000,a0
                       clrl     a0@
                       moveql   #2,d0
                       bsr      pulse_bit
                       bsr      test_bit
                       moveb    d0,sp@
                       moveql   #0x32,d0
                       bsr      pulse_bit
                       moveb    sp@,d0
                       addqw    #4,sp
                       rts

---------

a quick C prog to use with rc1.s:
>gcc -o rc1.o -c rc1.s
>gcc -c rrc.c
>gcc -o rrc rrc.o rc1.o
>rcc ...

perhaps a problem of register .. I think that 'read_time'
should save ALL the register on the stack 

You have to read the time many times to ensure to read the RIGHT
time. The 'read_time' routine isn't reliable.
Even in the rom of the board they do somethink like that:

-read time1         (1)
-wait 0.1 sec
-read time2
-wait 0.1 sec
-if time2<time1 goto 1

I use to put NBR = 9 because on some tests I got a bad date for
50% of the read :((

--rrc.c--

#include <stdio.h>
#include <stdlib.h>

extern unsigned long read_time (void);

#define NBR 9

int main (int argc, char *argv[])
{
  long time[NBR];
  long delta[NBR];
  register int id;
  register int i;
  register long ecart;

  for (id = 0; id < NBR; time[id++] = 0);
  for (id = 0; id < NBR - 1; delta[id++] = 10);
  id = 0;
  do
  {
    id = (id + 1 ) % NBR;
     for (i = 0; i <16990000L; i++);
    time[id] = read_time ();
    delta[id] = time[id] - time[(id -1) % NBR];
    if (delta[id] < 0)
      delta[id] = 50;
    ecart = 0;
    for (i = 0; i < NBR; ecart += delta[i++]);
  } while ((ecart < 0) && (ecart > NBR));

  printf ("%ld, %ld\n", time[id], ecart);
  for (i = 0; i < NBR; i++)
    printf ("%ld\n", delta[i]);

  return 0;
}

--------

just a test programm to read the Battclock with OS-call
and a quick'n dirty function to convert 'elapsed seconds'
to a date (perhaps a mistake for the year 2000)

--rc.c--

#include <stdio.h>
#include <stdlib.h>
#include <proto/exec.h>
#include <proto/battclock.h>

struct Node *BattClockBase;

unsigned long read_clock (void)
{
register unsigned long _res  __asm("d0");

  __asm __volatile ("jsr 0x0100358e"
  : "=r" (_res)
  :
  : "a0","a1","d0","d1", "memory");

  return _res;
}

#define an_n 31536000UL
#define an_b 31622400UL

void traite (unsigned long time)
{
int annee = 1978;
int mois  = 0;
int jour  = 0;
int heure = 0;
int minute = 0;
int seconde = 0;

unsigned long delta;
unsigned long j_mois[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

  if ( (annee % 4) == 0)
    delta = an_b;
  else
    delta = an_n;
  do
  {
    if (time >= delta)
    {
      time -= delta;
      annee++;
    }
    if ( (annee % 4) == 0)
      delta = an_b;
    else
      delta = an_n;
  } while (time >= delta);

  if (delta == an_b)
    j_mois[1] = 29;

  while ( time >= j_mois[mois] * 24 * 60 * 60)
  {
    time -= j_mois[mois] * 24 * 60 * 60;
    mois++;
  }
  mois++;

  while (time >= 24 * 60 * 60)
  {
    time -= 24 * 60 * 60;
    jour++;
  }
  jour++;

  while (time >= 60 * 60)
  {
    time -= 60 * 60;
    heure++;
  }

  while (time >= 60)
  {
    time -= 60;
    minute++;
  }

  seconde = time;

  printf (" -> le %02d/%02d/%4d à %02d:%02d:%02d\n",
          jour, mois, annee, heure, minute, seconde);
} /*      day   month year   hour   minute  second  */

int main (int argc, char *argv[])
{
unsigned long time_1;
unsigned long time_2;

  BattClockBase = OpenResource ("battclock.resource");
  if (BattClockBase != 0)
  {
    time_2 = ReadBattClock ();
    printf ("Valeur : %lud\n", time_2);
    traite (time_2);
  }
/*
  time_1 = read_clock();

  printf ("Valeur : %lud\n", time_1);
  traite (time_1);
*/
  return (0);
}

-----