OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [m68k/] [atari/] [config.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1623 jcastillo
/*
2
 *  linux/atari/config.c
3
 *
4
 *  Copyright (C) 1994 Bj”rn Brauel
5
 *
6
 *  5/2/94 Roman Hodek:
7
 *    Added setting of time_adj to get a better clock.
8
 *
9
 *  5/14/94 Roman Hodek:
10
 *    gettod() for TT
11
 *
12
 *  5/15/94 Roman Hodek:
13
 *    hard_reset_now() for Atari (and others?)
14
 *
15
 *  94/12/30 Andreas Schwab:
16
 *    atari_sched_init fixed to get precise clock.
17
 *
18
 * This file is subject to the terms and conditions of the GNU General Public
19
 * License.  See the file COPYING in the main directory of this archive
20
 * for more details.
21
 */
22
 
23
/*
24
 * Miscellaneous atari stuff
25
 */
26
 
27
#include <linux/config.h>
28
#include <linux/types.h>
29
#include <linux/mm.h>
30
#include <asm/bootinfo.h>
31
#include <linux/mc146818rtc.h>
32
#include <linux/kd.h>
33
#include <linux/tty.h>
34
#include <linux/console.h>
35
 
36
#include <asm/atarihw.h>
37
#include <asm/atarihdreg.h>
38
#include <asm/atariints.h>
39
 
40
#include <asm/system.h>
41
#include <asm/io.h>
42
#include <asm/irq.h>
43
#include <asm/pgtable.h>
44
#include <asm/machdep.h>
45
 
46
extern void atari_sched_init(isrfunc);
47
extern int atari_keyb_init(void);
48
extern int atari_kbdrate (struct kbd_repeat *);
49
extern void atari_kbd_leds (unsigned int);
50
extern void atari_init_INTS (void);
51
extern int atari_add_isr (unsigned long, isrfunc, int, void *, char *);
52
extern int atari_remove_isr (unsigned long, isrfunc, void *);
53
extern void atari_enable_irq (unsigned);
54
extern void atari_disable_irq (unsigned);
55
extern int atari_get_irq_list (char *buf, int len);
56
extern unsigned long atari_gettimeoffset (void);
57
extern void atari_mste_gettod (int *, int *, int *, int *, int *, int *);
58
extern void atari_gettod (int *, int *, int *, int *, int *, int *);
59
extern int atari_mste_hwclk (int, struct hwclk_time *);
60
extern int atari_hwclk (int, struct hwclk_time *);
61
extern int atari_mste_set_clock_mmss (unsigned long);
62
extern int atari_set_clock_mmss (unsigned long);
63
extern void atari_mksound( unsigned int count, unsigned int ticks );
64
extern void atari_reset( void );
65
#ifdef CONFIG_BLK_DEV_FD
66
extern int atari_floppy_init (void);
67
extern void atari_floppy_setup(char *, int *);
68
#endif
69
extern void atari_waitbut (void);
70
extern struct consw fb_con;
71
extern struct fb_info *atari_fb_init(long *);
72
extern void atari_debug_init (void);
73
extern void atari_video_setup(char *, int *);
74
 
75
extern void (*kd_mksound)(unsigned int, unsigned int);
76
 
77
/* This function tests for the presence of an address, specially a
78
 * hardware register address. It is called very early in the kernel
79
 * initialization process, when the VBR register isn't set up yet. On
80
 * an Atari, it still points to address 0, which is unmapped. So a bus
81
 * error would cause another bus error while fetching the exception
82
 * vector, and the CPU would do nothing at all. So we needed to set up
83
 * a temporary VBR and a vector table for the duration of the test.
84
 */
85
 
86
static int hwreg_present( volatile void *regp )
87
{
88
    int ret = 0;
89
    long        save_sp, save_vbr;
90
    long        tmp_vectors[3];
91
 
92
    __asm__ __volatile__
93
        (       "movec  %/vbr,%2\n\t"
94
                "movel  #Lberr1,%4@(8)\n\t"
95
                "movec  %4,%/vbr\n\t"
96
                "movel  %/sp,%1\n\t"
97
                "moveq  #0,%0\n\t"
98
                "tstb   %3@\n\t"
99
                "nop\n\t"
100
                "moveq  #1,%0\n"
101
                "Lberr1:\n\t"
102
                "movel  %1,%/sp\n\t"
103
                "movec  %2,%/vbr"
104
                : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
105
                : "a" (regp), "a" (tmp_vectors)
106
                );
107
 
108
    return( ret );
109
}
110
 
111
#if 0
112
static int hwreg_present_bywrite( volatile void *regp,
113
                                 unsigned char val )
114
 
115
{
116
    int         ret;
117
    long        save_sp, save_vbr;
118
    static long tmp_vectors[3] = { 0, 0, (long)&&after_test };
119
 
120
    __asm__ __volatile__
121
        (       "movec  %/vbr,%2\n\t"   /* save vbr value            */
122
                "movec  %4,%/vbr\n\t"   /* set up temporary vectors  */
123
                "movel  %/sp,%1\n\t"    /* save sp                   */
124
                "moveq  #0,%0\n\t"      /* assume not present        */
125
                "moveb  %5,%3@\n\t"     /* write the hardware reg    */
126
                "cmpb   %3@,%5\n\t"     /* compare it                */
127
                "seq    %0"             /* comes here only if reg    */
128
                                        /* is present                */
129
                : "=d&" (ret), "=r&" (save_sp), "=r&" (save_vbr)
130
                : "a" (regp), "r" (tmp_vectors), "d" (val)
131
                );
132
  after_test:
133
    __asm__ __volatile__
134
      ( "movel  %0,%/sp\n\t"            /* restore sp                */
135
        "movec  %1,%/vbr"                       /* restore vbr               */
136
        : : "r" (save_sp), "r" (save_vbr) : "sp"
137
        );
138
 
139
    return( ret );
140
}
141
#endif
142
 
143
/* Basically the same, but writes a value into a word register, protected
144
 * by a bus error handler */
145
 
146
static int hwreg_write( volatile void *regp, unsigned short val )
147
{
148
        int             ret;
149
        long    save_sp, save_vbr;
150
        long    tmp_vectors[3];
151
 
152
        __asm__ __volatile__
153
        (       "movec  %/vbr,%2\n\t"
154
                "movel  #Lberr2,%4@(8)\n\t"
155
                "movec  %4,%/vbr\n\t"
156
                "movel  %/sp,%1\n\t"
157
                "moveq  #0,%0\n\t"
158
                "movew  %5,%3@\n\t"
159
                "nop    \n\t"   /* If this nop isn't present, 'ret' may already be
160
                                 * loaded with 1 at the time the bus error
161
                                 * happens! */
162
                "moveq  #1,%0\n"
163
        "Lberr2:\n\t"
164
                "movel  %1,%/sp\n\t"
165
                "movec  %2,%/vbr"
166
                : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
167
                : "a" (regp), "a" (tmp_vectors), "g" (val)
168
        );
169
 
170
        return( ret );
171
}
172
 
173
/* ++roman: This is a more elaborate test for an SCC chip, since the plain
174
 * Medusa board generates DTACK at the SCC's standard addresses, but a SCC
175
 * board in the Medusa is possible. Also, the addresses where the ST_ESCC
176
 * resides generate DTACK without the chip, too.
177
 * The method is to write values into the interrupt vector register, that
178
 * should be readable without trouble (from channel A!).
179
 */
180
 
181
static int scc_test( volatile char *ctla )
182
{
183
        if (!hwreg_present( ctla ))
184
                return( 0 );
185
        MFPDELAY();
186
 
187
        *ctla = 2; MFPDELAY();
188
        *ctla = 0x40; MFPDELAY();
189
 
190
        *ctla = 2; MFPDELAY();
191
        if (*ctla != 0x40) return( 0 );
192
        MFPDELAY();
193
 
194
        *ctla = 2; MFPDELAY();
195
        *ctla = 0x60; MFPDELAY();
196
 
197
        *ctla = 2; MFPDELAY();
198
        if (*ctla != 0x60) return( 0 );
199
 
200
        return( 1 );
201
}
202
 
203
void config_atari(void)
204
{
205
    mach_sched_init      = atari_sched_init;
206
    mach_keyb_init       = atari_keyb_init;
207
    mach_kbdrate         = atari_kbdrate;
208
    mach_kbd_leds        = atari_kbd_leds;
209
    mach_init_INTS       = atari_init_INTS;
210
    mach_add_isr         = atari_add_isr;
211
    mach_remove_isr      = atari_remove_isr;
212
    mach_enable_irq      = atari_enable_irq;
213
    mach_disable_irq     = atari_disable_irq;
214
    mach_get_irq_list    = atari_get_irq_list;
215
    mach_gettimeoffset   = atari_gettimeoffset;
216
    mach_mksound         = atari_mksound;
217
    mach_reset           = atari_reset;
218
#ifdef CONFIG_BLK_DEV_FD
219
    mach_floppy_init     = atari_floppy_init;
220
    mach_floppy_setup    = atari_floppy_setup;
221
#endif
222
    conswitchp           = &fb_con;
223
    waitbut              = atari_waitbut;
224
    mach_fb_init         = atari_fb_init;
225
    mach_max_dma_address = 0xffffff;
226
    mach_debug_init      = atari_debug_init;
227
    mach_video_setup     = atari_video_setup;
228
    kd_mksound           = atari_mksound;
229
 
230
    /* ++bjoern:
231
     * Determine hardware present
232
     */
233
 
234
    printk( "Atari hardware found: " );
235
    if (is_medusa) {
236
        /* There's no Atari video hardware on the Medusa, but all the
237
         * addresses below generate a DTACK so no bus error occurs! */
238
    }
239
    else if (hwreg_present( f030_xreg )) {
240
        ATARIHW_SET(VIDEL_SHIFTER);
241
        printk( "VIDEL " );
242
        /* This is a temporary hack: If there is Falcon video
243
         * hardware, we assume that the ST-DMA serves SCSI instead of
244
         * ACSI. In the future, there should be a better method for
245
         * this...
246
         */
247
        ATARIHW_SET(ST_SCSI);
248
        printk( "STDMA-SCSI " );
249
    }
250
    else if (hwreg_present( tt_palette )) {
251
        ATARIHW_SET(TT_SHIFTER);
252
        printk( "TT_SHIFTER " );
253
    }
254
    else if (hwreg_present( &shifter.bas_hi )) {
255
        if (hwreg_present( &shifter.bas_lo ) &&
256
            (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) {
257
            ATARIHW_SET(EXTD_SHIFTER);
258
            printk( "EXTD_SHIFTER " );
259
        }
260
        else {
261
            ATARIHW_SET(STND_SHIFTER);
262
            printk( "STND_SHIFTER " );
263
        }
264
    }
265
    if (hwreg_present( &mfp.par_dt_reg )) {
266
        ATARIHW_SET(ST_MFP);
267
        printk( "ST_MFP " );
268
    }
269
    if (hwreg_present( &tt_mfp.par_dt_reg )) {
270
        ATARIHW_SET(TT_MFP);
271
        printk( "TT_MFP " );
272
    }
273
    if (hwreg_present( &tt_scsi_dma.dma_addr_hi )) {
274
        ATARIHW_SET(SCSI_DMA);
275
        printk( "TT_SCSI_DMA " );
276
    }
277
    if (hwreg_present( &st_dma.dma_hi )) {
278
        ATARIHW_SET(STND_DMA);
279
        printk( "STND_DMA " );
280
    }
281
    if (is_medusa || /* The ST-DMA address registers aren't readable
282
                      * on all Medusas, so the test below may fail */
283
        (hwreg_present( &st_dma.dma_vhi ) &&
284
         (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) &&
285
         st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa &&
286
         (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) &&
287
         st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) {
288
        ATARIHW_SET(EXTD_DMA);
289
        printk( "EXTD_DMA " );
290
    }
291
    if (hwreg_present( &tt_scsi.scsi_data )) {
292
        ATARIHW_SET(TT_SCSI);
293
        printk( "TT_SCSI " );
294
    }
295
    if (hwreg_present( &sound_ym.rd_data_reg_sel )) {
296
        ATARIHW_SET(YM_2149);
297
        printk( "YM2149 " );
298
    }
299
    if (!is_medusa && hwreg_present( &tt_dmasnd.ctrl )) {
300
        ATARIHW_SET(PCM_8BIT);
301
        printk( "PCM " );
302
    }
303
    if (hwreg_present( (void *)(0xffff8940) )) {
304
        ATARIHW_SET(CODEC);
305
        printk( "CODEC " );
306
    }
307
    if (hwreg_present( &tt_scc_dma.dma_ctrl ) &&
308
#if 0
309
        /* This test sucks! Who knows some better? */
310
        (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
311
        (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
312
#else
313
        !is_medusa
314
#endif
315
        ) {
316
        ATARIHW_SET(SCC_DMA);
317
        printk( "SCC_DMA " );
318
    }
319
    if (scc_test( &scc.cha_a_ctrl )) {
320
        ATARIHW_SET(SCC);
321
        printk( "SCC " );
322
    }
323
    if (scc_test( &st_escc.cha_b_ctrl )) {
324
        ATARIHW_SET( ST_ESCC );
325
        printk( "ST_ESCC " );
326
    }
327
    if (hwreg_present( &tt_scu.sys_mask )) {
328
        ATARIHW_SET(SCU);
329
        /* Assume a VME bus if there's a SCU */
330
        ATARIHW_SET( VME );
331
        printk( "VME SCU " );
332
    }
333
    if (hwreg_present( (void *)(0xffff9210) )) {
334
        ATARIHW_SET(ANALOG_JOY);
335
        printk( "ANALOG_JOY " );
336
    }
337
    if (hwreg_present( blitter.halftone )) {
338
        ATARIHW_SET(BLITTER);
339
        printk( "BLITTER " );
340
    }
341
    if (hwreg_present( (void *)(ATA_HD_BASE+ATA_HD_CMD) )) {
342
        ATARIHW_SET(IDE);
343
        printk( "IDE " );
344
    }
345
#if 1 /* This maybe wrong */
346
    if (!is_medusa &&
347
        hwreg_present( &tt_microwire.data ) &&
348
        hwreg_present( &tt_microwire.mask ) &&
349
        (tt_microwire.mask = 0x7ff,
350
         tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR,
351
         tt_microwire.data != 0)) {
352
        ATARIHW_SET(MICROWIRE);
353
        while (tt_microwire.mask != 0x7ff) ;
354
        printk( "MICROWIRE " );
355
    }
356
#endif
357
    if (hwreg_present( &tt_rtc.regsel )) {
358
        ATARIHW_SET(TT_CLK);
359
        printk( "TT_CLK " );
360
        mach_gettod = atari_gettod;
361
        mach_hwclk = atari_hwclk;
362
        mach_set_clock_mmss = atari_set_clock_mmss;
363
    }
364
    if (hwreg_present( &mste_rtc.sec_ones)) {
365
        ATARIHW_SET(MSTE_CLK);
366
        printk( "MSTE_CLK ");
367
        mach_gettod = atari_mste_gettod;
368
        mach_hwclk = atari_mste_hwclk;
369
        mach_set_clock_mmss = atari_mste_set_clock_mmss;
370
    }
371
    if (!is_medusa &&
372
        hwreg_present( &dma_wd.fdc_speed ) &&
373
        hwreg_write( &dma_wd.fdc_speed, 0 )) {
374
            ATARIHW_SET(FDCSPEED);
375
            printk( "FDC_SPEED ");
376
    }
377
    if (!ATARIHW_PRESENT(ST_SCSI)) {
378
        ATARIHW_SET(ACSI);
379
        printk( "ACSI " );
380
    }
381
    printk("\n");
382
 
383
    if (m68k_is040or060)
384
        /* Now it seems to be safe to turn of the tt0 transparent
385
         * translation (the one that must not be turned off in
386
         * head.S...)
387
         */
388
        __asm__ volatile ("moveq #0,%/d0;"
389
                          ".long 0x4e7b0004;"   /* movec d0,itt0 */
390
                          ".long 0x4e7b0006;"   /* movec d0,dtt0 */
391
                                                  : /* no outputs */
392
                                                  : /* no inputs */
393
                                                  : "d0");
394
 
395
    /* allocator for memory that must reside in st-ram */
396
    atari_stram_init ();
397
 
398
    /* Set up a mapping for the VMEbus address region:
399
     *
400
     * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff
401
     * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at
402
     * 0xfe000000 virt., because this can be done with a single
403
     * transparent translation. On the 68040, lots of often unused
404
     * page tables would be needed otherwise. On a MegaSTE or similar,
405
     * the highest byte is stripped off by hardware due to the 24 bit
406
     * design of the bus.
407
     */
408
 
409
    if (!m68k_is040or060) {
410
        unsigned long   tt1_val;
411
        tt1_val = 0xfe008543;   /* Translate 0xfexxxxxx, enable, cache
412
                                 * inhibit, read and write, FDC mask = 3,
413
                                 * FDC val = 4 -> Supervisor only */
414
        __asm__ __volatile__ ( "pmove   %0@,%/tt1" : : "a" (&tt1_val) );
415
    }
416
    else {
417
        __asm__ __volatile__
418
            ( "movel %0,%/d0\n\t"
419
              ".long 0x4e7b0005\n\t"    /* movec d0,itt1 */
420
              ".long 0x4e7b0007"        /* movec d0,dtt1 */
421
              :
422
              : "g" (0xfe00a040)        /* Translate 0xfexxxxxx, enable,
423
                                         * supervisor only, non-cacheable/
424
                                         * serialized, writable */
425
              : "d0" );
426
 
427
    }
428
}
429
 
430
void atari_sched_init (isrfunc timer_routine)
431
{
432
    /* set Timer C data Register */
433
    mfp.tim_dt_c = INT_TICKS;
434
    /* start timer C, div = 1:100 */
435
    mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60;
436
    /* install interrupt service routine for MFP Timer C */
437
    add_isr (IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, NULL, "timer");
438
}
439
 
440
/* ++andreas: gettimeoffset fixed to check for pending interrupt */
441
 
442
#define TICK_SIZE 10000
443
 
444
/* This is always executed with interrupts disabled.  */
445
unsigned long atari_gettimeoffset (void)
446
{
447
  unsigned long ticks, offset = 0;
448
 
449
  /* read MFP timer C current value */
450
  ticks = mfp.tim_dt_c;
451
  /* The probability of underflow is less than 2% */
452
  if (ticks > INT_TICKS - INT_TICKS / 50)
453
    /* Check for pending timer interrupt */
454
    if (mfp.int_pn_b & (1 << 5))
455
      offset = TICK_SIZE;
456
 
457
  ticks = INT_TICKS - ticks;
458
  ticks = ticks * 10000L / INT_TICKS;
459
 
460
  return ticks + offset;
461
}
462
 
463
 
464
static void
465
mste_read(struct MSTE_RTC *val)
466
{
467
#define COPY(v) val->v=(mste_rtc.v & 0xf)
468
        do {
469
                COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
470
                COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
471
                COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
472
                COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
473
                COPY(year_tens) ;
474
        /* prevent from reading the clock while it changed */
475
        } while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
476
#undef COPY
477
}
478
 
479
static void
480
mste_write(struct MSTE_RTC *val)
481
{
482
#define COPY(v) mste_rtc.v=val->v
483
        do {
484
                COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
485
                COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
486
                COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
487
                COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
488
                COPY(year_tens) ;
489
        /* prevent from writing the clock while it changed */
490
        } while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
491
#undef COPY
492
}
493
 
494
#define RTC_READ(reg)                           \
495
    ({  unsigned char   __val;                  \
496
                outb(reg,&tt_rtc.regsel);       \
497
                __val = tt_rtc.data;            \
498
                __val;                          \
499
        })
500
 
501
#define RTC_WRITE(reg,val)                      \
502
    do {                                        \
503
                outb(reg,&tt_rtc.regsel);       \
504
                tt_rtc.data = (val);            \
505
        } while(0)
506
 
507
 
508
void atari_mste_gettod (int *yearp, int *monp, int *dayp,
509
                        int *hourp, int *minp, int *secp)
510
{
511
    int hr24=0;
512
    struct MSTE_RTC val;
513
 
514
    mste_rtc.mode=(mste_rtc.mode | 1);
515
    hr24=mste_rtc.mon_tens & 1;
516
    mste_rtc.mode=(mste_rtc.mode & ~1);
517
 
518
    mste_read(&val);
519
    *secp = val.sec_ones + val.sec_tens * 10;
520
    *minp = val.min_ones + val.min_tens * 10;
521
    if (hr24)
522
        *hourp = val.hr_ones + val.hr_tens * 10;
523
    else {
524
        *hourp = val.hr_ones + (val.hr_tens & 1) * 10;
525
        if (val.hr_tens & 2)
526
            *hourp += 12;
527
    }
528
    *dayp = val.day_ones + val.day_tens * 10;
529
    *monp = val.mon_ones + val.mon_tens * 10;
530
    *yearp = val.year_ones + val.year_tens * 10 + 80;
531
}
532
 
533
 
534
void atari_gettod (int *yearp, int *monp, int *dayp,
535
                   int *hourp, int *minp, int *secp)
536
{
537
    unsigned char       ctrl;
538
    unsigned short tos_version;
539
 
540
    while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ;
541
    while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ;
542
 
543
    *secp  = RTC_READ(RTC_SECONDS);
544
    *minp  = RTC_READ(RTC_MINUTES);
545
    *hourp = RTC_READ(RTC_HOURS);
546
    *dayp  = RTC_READ(RTC_DAY_OF_MONTH);
547
    *monp  = RTC_READ(RTC_MONTH);
548
    *yearp = RTC_READ(RTC_YEAR);
549
 
550
    ctrl = RTC_READ(RTC_CONTROL);
551
 
552
    if (!(ctrl & RTC_DM_BINARY)) {
553
        BCD_TO_BIN(*secp);
554
        BCD_TO_BIN(*minp);
555
        BCD_TO_BIN(*hourp);
556
        BCD_TO_BIN(*dayp);
557
        BCD_TO_BIN(*monp);
558
        BCD_TO_BIN(*yearp);
559
    }
560
    if (!(ctrl & RTC_24H)) {
561
        if (*hourp & 0x80) {
562
            *hourp &= ~0x80;
563
            *hourp += 12;
564
        }
565
    }
566
    /* Adjust values (let the setup valid) */
567
 
568
    /* Fetch tos version at Physical 2 */
569
    /* We my not be able to access this address if the kernel is
570
       loaded to st ram, since the first page is unmapped.  On the
571
       Medusa this is always the case and there is nothing we can do
572
       about this, so we just assume the smaller offset.  For the TT
573
       we use the fact that in head.S we have set up a mapping
574
       0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
575
       in the last 16MB of the address space. */
576
    tos_version = is_medusa ? 0xfff : *(unsigned short *)0xFF000002;
577
    *yearp += (tos_version < 0x306) ? 70 : 68;
578
}
579
 
580
#define HWCLK_POLL_INTERVAL     5
581
 
582
int atari_mste_hwclk( int op, struct hwclk_time *t )
583
{
584
    int hour, year;
585
    int hr24=0;
586
    struct MSTE_RTC val;
587
 
588
    mste_rtc.mode=(mste_rtc.mode | 1);
589
    hr24=mste_rtc.mon_tens & 1;
590
    mste_rtc.mode=(mste_rtc.mode & ~1);
591
 
592
    if (op) {
593
        /* write: prepare values */
594
 
595
        val.sec_ones = t->sec % 10;
596
        val.sec_tens = t->sec / 10;
597
        val.min_ones = t->min % 10;
598
        val.min_tens = t->min / 10;
599
        hour = t->hour;
600
        val.hr_ones = hour % 10;
601
        val.hr_tens = hour / 10;
602
        if (!hr24  && hour > 11) {
603
            hour -= 12;
604
            val.hr_ones = hour % 10;
605
            val.hr_tens = (hour / 10) | 2;
606
        }
607
        val.day_ones = t->day % 10;
608
        val.day_tens = t->day / 10;
609
        val.mon_ones = (t->mon+1) % 10;
610
        val.mon_tens = (t->mon+1) / 10;
611
        year = t->year - 80;
612
        val.year_ones = year % 10;
613
        val.year_tens = year / 10;
614
        val.weekday = t->wday;
615
        mste_write(&val);
616
        mste_rtc.mode=(mste_rtc.mode | 1);
617
        val.year_ones = (year % 4);     /* leap year register */
618
        mste_rtc.mode=(mste_rtc.mode & ~1);
619
    }
620
    else {
621
        mste_read(&val);
622
        t->sec = val.sec_ones + val.sec_tens * 10;
623
        t->min = val.min_ones + val.min_tens * 10;
624
        if (hr24)
625
            t->hour = val.hr_ones + val.hr_tens * 10;
626
        else {
627
            t->hour = val.hr_ones + (val.hr_tens & 1) * 10;
628
            if (val.hr_tens & 2)
629
                t->hour += 12;
630
        }
631
        t->day = val.day_ones + val.day_tens * 10;
632
        t->mon = val.mon_ones + val.mon_tens * 10 - 1;
633
        t->year = val.year_ones + val.year_tens * 10 + 80;
634
        t->wday = val.weekday;
635
    }
636
    return 0;
637
}
638
 
639
int atari_hwclk( int op, struct hwclk_time *t )
640
{
641
    int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
642
    unsigned long       flags;
643
    unsigned short      tos_version;
644
    unsigned char       ctrl;
645
 
646
    /* Tos version at Physical 2.  See above for explanation why we
647
       cannot use PTOV(2).  */
648
    tos_version = is_medusa ? 0xfff : *(unsigned short *)0xff000002;
649
 
650
    ctrl = RTC_READ(RTC_CONTROL); /* control registers are
651
                                   * independent from the UIP */
652
 
653
    if (op) {
654
        /* write: prepare values */
655
 
656
        sec  = t->sec;
657
        min  = t->min;
658
        hour = t->hour;
659
        day  = t->day;
660
        mon  = t->mon + 1;
661
        year = t->year - ((tos_version < 0x306) ? 70 : 68);
662
        wday = t->wday + (t->wday >= 0);
663
 
664
        if (!(ctrl & RTC_24H) && hour > 11) {
665
            hour -= 12;
666
            hour |= 0x80;
667
        }
668
 
669
        if (!(ctrl & RTC_DM_BINARY)) {
670
            BIN_TO_BCD(sec);
671
            BIN_TO_BCD(min);
672
            BIN_TO_BCD(hour);
673
            BIN_TO_BCD(day);
674
            BIN_TO_BCD(mon);
675
            BIN_TO_BCD(year);
676
            if (wday >= 0) BIN_TO_BCD(wday);
677
        }
678
    }
679
 
680
    /* Reading/writing the clock registers is a bit critical due to
681
     * the regular update cycle of the RTC. While an update is in
682
     * progress, registers 0..9 shouldn't be touched.
683
     * The problem is solved like that: If an update is currently in
684
     * progress (the UIP bit is set), the process sleeps for a while
685
     * (50ms). This really should be enough, since the update cycle
686
     * normally needs 2 ms.
687
     * If the UIP bit reads as 0, we have at least 244 usecs until the
688
     * update starts. This should be enough... But to be sure,
689
     * additionally the RTC_SET bit is set to prevent an update cycle.
690
     */
691
 
692
    while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
693
        current->state = TASK_INTERRUPTIBLE;
694
        current->timeout = jiffies + HWCLK_POLL_INTERVAL;
695
        schedule();
696
    }
697
 
698
    save_flags(flags);
699
    cli();
700
    RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
701
    if (!op) {
702
        sec  = RTC_READ( RTC_SECONDS );
703
        min  = RTC_READ( RTC_MINUTES );
704
        hour = RTC_READ( RTC_HOURS );
705
        day  = RTC_READ( RTC_DAY_OF_MONTH );
706
        mon  = RTC_READ( RTC_MONTH );
707
        year = RTC_READ( RTC_YEAR );
708
        wday = RTC_READ( RTC_DAY_OF_WEEK );
709
    }
710
    else {
711
        RTC_WRITE( RTC_SECONDS, sec );
712
        RTC_WRITE( RTC_MINUTES, min );
713
        RTC_WRITE( RTC_HOURS, hour );
714
        RTC_WRITE( RTC_DAY_OF_MONTH, day );
715
        RTC_WRITE( RTC_MONTH, mon );
716
        RTC_WRITE( RTC_YEAR, year );
717
        if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
718
    }
719
    RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
720
    restore_flags(flags);
721
 
722
    if (!op) {
723
        /* read: adjust values */
724
 
725
        if (!(ctrl & RTC_DM_BINARY)) {
726
            BCD_TO_BIN(sec);
727
            BCD_TO_BIN(min);
728
            BCD_TO_BIN(hour);
729
            BCD_TO_BIN(day);
730
            BCD_TO_BIN(mon);
731
            BCD_TO_BIN(year);
732
            BCD_TO_BIN(wday);
733
        }
734
 
735
        if (!(ctrl & RTC_24H)) {
736
            if (hour & 0x80) {
737
                hour &= ~0x80;
738
                hour += 12;
739
            }
740
        }
741
 
742
        t->sec  = sec;
743
        t->min  = min;
744
        t->hour = hour;
745
        t->day  = day;
746
        t->mon  = mon - 1;
747
        t->year = year + ((tos_version < 0x306) ? 70 : 68);
748
        t->wday = wday - 1;
749
    }
750
 
751
    return( 0 );
752
}
753
 
754
 
755
int atari_mste_set_clock_mmss (unsigned long nowtime)
756
{
757
    short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
758
    struct MSTE_RTC val;
759
    unsigned char rtc_minutes;
760
 
761
    mste_read(&val);
762
    rtc_minutes= val.min_ones + val.min_tens * 10;
763
    if ((rtc_minutes < real_minutes
764
         ? real_minutes - rtc_minutes
765
         : rtc_minutes - real_minutes) < 30)
766
    {
767
        val.sec_ones = real_seconds % 10;
768
        val.sec_tens = real_seconds / 10;
769
        val.min_ones = real_minutes % 10;
770
        val.min_tens = real_minutes / 10;
771
        mste_write(&val);
772
    }
773
    else
774
        return -1;
775
    return 0;
776
}
777
 
778
int atari_set_clock_mmss (unsigned long nowtime)
779
{
780
    int retval = 0;
781
    short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
782
    unsigned char save_control, save_freq_select, rtc_minutes;
783
 
784
    save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
785
    RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);
786
 
787
    save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */
788
    RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2);
789
 
790
    rtc_minutes = RTC_READ (RTC_MINUTES);
791
    if (!(save_control & RTC_DM_BINARY))
792
        BCD_TO_BIN (rtc_minutes);
793
 
794
    /* Since we're only adjusting minutes and seconds, don't interfere
795
       with hour overflow.  This avoids messing with unknown time zones
796
       but requires your RTC not to be off by more than 30 minutes.  */
797
    if ((rtc_minutes < real_minutes
798
         ? real_minutes - rtc_minutes
799
         : rtc_minutes - real_minutes) < 30)
800
        {
801
            if (!(save_control & RTC_DM_BINARY))
802
                {
803
                    BIN_TO_BCD (real_seconds);
804
                    BIN_TO_BCD (real_minutes);
805
                }
806
            RTC_WRITE (RTC_SECONDS, real_seconds);
807
            RTC_WRITE (RTC_MINUTES, real_minutes);
808
        }
809
    else
810
        retval = -1;
811
 
812
    RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
813
    RTC_WRITE (RTC_CONTROL, save_control);
814
    return retval;
815
}
816
 
817
 
818
void atari_waitbut (void)
819
{
820
    /* sorry, no-op */
821
}
822
 
823
 
824
static inline void ata_mfp_out (char c)
825
{
826
    while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */
827
        barrier ();
828
    mfp.usart_dta = c;
829
}
830
 
831
void ata_mfp_print (const char *str)
832
{
833
    for( ; *str; ++str ) {
834
        if (*str == '\n')
835
            ata_mfp_out( '\r' );
836
        ata_mfp_out( *str );
837
    }
838
}
839
 
840
static inline void ata_scc_out (char c)
841
{
842
    do {
843
        MFPDELAY();
844
    } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
845
    MFPDELAY();
846
    scc.cha_b_data = c;
847
}
848
 
849
void ata_scc_print (const char *str)
850
{
851
    for( ; *str; ++str ) {
852
        if (*str == '\n')
853
            ata_scc_out( '\r' );
854
        ata_scc_out( *str );
855
    }
856
}
857
 
858
static int ata_par_out (char c)
859
{
860
    extern unsigned long loops_per_sec;
861
    unsigned char tmp;
862
    /* This a some-seconds timeout in case no printer is connected */
863
    unsigned long i = loops_per_sec > 1 ? loops_per_sec : 10000000;
864
 
865
    while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */
866
        ;
867
    if (!i) return( 0 );
868
 
869
    sound_ym.rd_data_reg_sel = 15;  /* select port B */
870
    sound_ym.wd_data = c;           /* put char onto port */
871
    sound_ym.rd_data_reg_sel = 14;  /* select port A */
872
    tmp = sound_ym.rd_data_reg_sel;
873
    sound_ym.wd_data = tmp & ~0x20; /* set strobe L */
874
    MFPDELAY();                     /* wait a bit */
875
    sound_ym.wd_data = tmp | 0x20;  /* set strobe H */
876
    return( 1 );
877
}
878
 
879
void ata_par_print (const char *str)
880
{
881
    static int printer_present = 1;
882
 
883
    if (!printer_present)
884
        return;
885
 
886
    for( ; *str; ++str ) {
887
        if (*str == '\n')
888
            if (!ata_par_out( '\r' )) {
889
                printer_present = 0;
890
                return;
891
            }
892
        if (!ata_par_out( *str )) {
893
            printer_present = 0;
894
            return;
895
        }
896
    }
897
}
898
 
899
 
900
void atari_debug_init( void )
901
{
902
    extern void (*debug_print_proc)(const char *);
903
    extern char m68k_debug_device[];
904
 
905
    if (!strcmp( m68k_debug_device, "ser" )) {
906
        /* defaults to ser2 for a Falcon and ser1 otherwise */
907
        strcpy( m68k_debug_device,
908
                ((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_FALCON) ?
909
                "ser2" : "ser1" );
910
 
911
    }
912
 
913
    if (!strcmp( m68k_debug_device, "ser1" )) {
914
        /* ST-MFP Modem1 serial port */
915
        mfp.trn_stat  &= ~0x01; /* disable TX */
916
        mfp.usart_ctr  = 0x88;  /* clk 1:16, 8N1 */
917
        mfp.tim_ct_cd &= 0x70;  /* stop timer D */
918
        mfp.tim_dt_d   = 2;     /* 9600 bps */
919
        mfp.tim_ct_cd |= 0x01;  /* start timer D, 1:4 */
920
        mfp.trn_stat  |= 0x01;  /* enable TX */
921
        debug_print_proc = ata_mfp_print;
922
    }
923
    else if (!strcmp( m68k_debug_device, "ser2" )) {
924
        /* SCC Modem2 serial port */
925
        static unsigned char *p, scc_table[] = {
926
            9, 12,              /* Reset */
927
            4, 0x44,            /* x16, 1 stopbit, no parity */
928
            3, 0xc0,            /* receiver: 8 bpc */
929
            5, 0xe2,            /* transmitter: 8 bpc, assert dtr/rts */
930
            9, 0,                /* no interrupts */
931
            10, 0,               /* NRZ */
932
            11, 0x50,           /* use baud rate generator */
933
            12, 24, 13, 0,       /* 9600 baud */
934
            14, 2, 14, 3,       /* use master clock for BRG, enable */
935
            3, 0xc1,            /* enable receiver */
936
            5, 0xea,            /* enable transmitter */
937
 
938
        };
939
 
940
        (void)scc.cha_b_ctrl; /* reset reg pointer */
941
        for( p = scc_table; *p != 0; ) {
942
            scc.cha_b_ctrl = *p++;
943
            MFPDELAY();
944
            scc.cha_b_ctrl = *p++;
945
            MFPDELAY();
946
        }
947
        debug_print_proc = ata_scc_print;
948
    }
949
    else if (!strcmp( m68k_debug_device, "par" )) {
950
        /* parallel printer */
951
        atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */
952
        sound_ym.rd_data_reg_sel = 7;  /* select mixer control */
953
        sound_ym.wd_data = 0xff;       /* sound off, ports are output */
954
        sound_ym.rd_data_reg_sel = 15; /* select port B */
955
        sound_ym.wd_data = 0;          /* no char */
956
        sound_ym.rd_data_reg_sel = 14; /* select port A */
957
        sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */
958
        debug_print_proc = ata_par_print;
959
    }
960
    else
961
        debug_print_proc = NULL;
962
}
963
 
964
 
965
void ata_serial_print (const char *str)
966
{
967
  int c;
968
 
969
  while (c = *str++, c != 0)
970
    {
971
      if (c == '\n')
972
        {
973
          while (!(mfp.trn_stat & (1 << 7)))
974
            barrier ();
975
          mfp.usart_dta = '\r';
976
        }
977
      while (!(mfp.trn_stat & (1 << 7)))
978
        barrier ();
979
      mfp.usart_dta = c;
980
    }
981
}
982
 
983
/* ++roman:
984
 *
985
 * This function does a reset on machines that lack the ability to
986
 * assert the processor's _RESET signal somehow via hardware. It is
987
 * based on the fact that you can find the initial SP and PC values
988
 * after a reset at physical addresses 0 and 4. This works pretty well
989
 * for Atari machines, since the lowest 8 bytes of physical memory are
990
 * really ROM (mapped by hardware). For other 680x0 machines: don't
991
 * know if it works...
992
 *
993
 * To get the values at addresses 0 and 4, the MMU better is turned
994
 * off first. After that, we have to jump into physical address space
995
 * (the PC before the pmove statement points to the virtual address of
996
 * the code). Getting that physical address is not hard, but the code
997
 * becomes a bit complex since I've tried to ensure that the jump
998
 * statement after the pmove is in the cache already (otherwise the
999
 * processor can't fetch it!). For that, the code first jumps to the
1000
 * jump statement with the (virtual) address of the pmove section in
1001
 * an address register . The jump statement is surely in the cache
1002
 * now. After that, that physical address of the reset code is loaded
1003
 * into the same address register, pmove is done and the same jump
1004
 * statements goes to the reset code. Since there are not many
1005
 * statements between the two jumps, I hope it stays in the cache.
1006
 *
1007
 * The C code makes heavy use of the GCC features that you can get the
1008
 * address of a C label. No hope to compile this with another compiler
1009
 * than GCC!
1010
 */
1011
 
1012
/* ++andreas: no need for complicated code, just depend on prefetch */
1013
 
1014
void atari_reset (void)
1015
{
1016
    long tc_val = 0;
1017
    long reset_addr;
1018
 
1019
    /* On the Medusa, phys. 0x4 may contain garbage because it's no
1020
       ROM.  See above for explanation why we cannot use PTOV(4). */
1021
    reset_addr = is_medusa ? 0xe00030 : *(unsigned long *) 0xff000004;
1022
 
1023
    acia.key_ctrl = ACIA_RESET;             /* reset ACIA for switch off OverScan, if it's active */
1024
 
1025
    /* processor independent: turn off interrupts and reset the VBR;
1026
     * the caches must be left enabled, else prefetching the final jump
1027
     * instruction doesn't work. */
1028
    cli();
1029
    __asm__ __volatile__
1030
        ("moveq #0,%/d0\n\t"
1031
         "movec %/d0,%/vbr"
1032
         : : : "d0" );
1033
 
1034
    if (m68k_is040or060) {
1035
        unsigned long jmp_addr040 = VTOP(&&jmp_addr_label040);
1036
        if (m68k_is040or060 == 6) {
1037
            /* 68060: clear PCR to turn off superscalar operation */
1038
            __asm__ __volatile__
1039
                ("moveq #0,%/d0\n\t"
1040
                 ".long 0x4e7b0808"     /* movec d0,pcr */
1041
                 : : : "d0" );
1042
        }
1043
 
1044
        __asm__ __volatile__
1045
            ("movel    %0,%/d0\n\t"
1046
             "andl     #0xff000000,%/d0\n\t"
1047
             "orw      #0xe020,%/d0\n\t"   /* map 16 MB, enable, cacheable */
1048
             ".long    0x4e7b0004\n\t"   /* movec d0,itt0 */
1049
             ".long    0x4e7b0006\n\t"   /* movec d0,dtt0 */
1050
             "jmp   %0@\n\t"
1051
             : /* no outputs */
1052
             : "a" (jmp_addr040)
1053
             : "d0" );
1054
      jmp_addr_label040:
1055
        __asm__ __volatile__
1056
          ("moveq #0,%/d0\n\t"
1057
           "nop\n\t"
1058
           ".word 0xf4d8\n\t"           /* cinva i/d */
1059
           ".word 0xf518\n\t"           /* pflusha */
1060
           ".long 0x4e7b0003\n\t"       /* movec d0,tc */
1061
           "jmp %0@"
1062
           : /* no outputs */
1063
           : "a" (reset_addr)
1064
           : "d0");
1065
    }
1066
    else
1067
        __asm__ __volatile__
1068
            ("pmove %0@,%/tc\n\t"
1069
             "jmp %1@"
1070
             : /* no outputs */
1071
             : "a" (&tc_val), "a" (reset_addr));
1072
}
1073
 
1074
 
1075
void atari_get_model(char *model)
1076
{
1077
    strcpy(model, "Atari ");
1078
    switch (boot_info.bi_atari.mch_cookie >> 16) {
1079
        case ATARI_MCH_ST:
1080
            if (ATARIHW_PRESENT(MSTE_CLK))
1081
                strcat (model, "Mega ST");
1082
            else
1083
                strcat (model, "ST");
1084
            break;
1085
        case ATARI_MCH_STE:
1086
            if ((boot_info.bi_atari.mch_cookie & 0xffff) == 0x10)
1087
                strcat (model, "Mega STE");
1088
            else
1089
                strcat (model, "STE");
1090
            break;
1091
        case ATARI_MCH_TT:
1092
            if (is_medusa)
1093
                /* Medusa has TT _MCH cookie */
1094
                strcat (model, "Medusa");
1095
            else
1096
                strcat (model, "TT");
1097
            break;
1098
        case ATARI_MCH_FALCON:
1099
            strcat (model, "Falcon");
1100
            break;
1101
        default:
1102
            sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)",
1103
                     boot_info.bi_atari.mch_cookie);
1104
            break;
1105
    }
1106
}
1107
 
1108
 
1109
int atari_get_hardware_list(char *buffer)
1110
{
1111
    int len = 0, i;
1112
 
1113
    for (i = 0; i < boot_info.num_memory; i++)
1114
        len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n",
1115
                        boot_info.memory[i].size >> 20,
1116
                        boot_info.memory[i].addr,
1117
                        (boot_info.memory[i].addr & 0xff000000 ?
1118
                         "alternate RAM" : "ST-RAM"));
1119
 
1120
#define ATARIHW_ANNOUNCE(name,str)                              \
1121
    if (ATARIHW_PRESENT(name))                  \
1122
        len += sprintf (buffer + len, "\t%s\n", str)
1123
 
1124
    len += sprintf (buffer + len, "Detected hardware:\n");
1125
    ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter");
1126
    ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter");
1127
    ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter");
1128
    ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter");
1129
    ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator");
1130
    ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound");
1131
    ATARIHW_ANNOUNCE(CODEC, "CODEC Sound");
1132
    ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)");
1133
    ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)");
1134
    ATARIHW_ANNOUNCE(ACSI, "ACSI Interface");
1135
    ATARIHW_ANNOUNCE(IDE, "IDE Interface");
1136
    ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC");
1137
    ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901");
1138
    ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901");
1139
    ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530");
1140
    ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230");
1141
    ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface");
1142
    ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface");
1143
    ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)");
1144
    ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)");
1145
    ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380");
1146
    ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC");
1147
    ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A");
1148
    ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15");
1149
    ATARIHW_ANNOUNCE(SCU, "System Control Unit");
1150
    ATARIHW_ANNOUNCE(BLITTER, "Blitter");
1151
    ATARIHW_ANNOUNCE(VME, "VME Bus");
1152
 
1153
    return(len);
1154
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.