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);
}
-----