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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [char/] [dtlk.c] - Blame information for rev 65

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

Line No. Rev Author Line
1 62 marcus.erl
/*                                              -*- linux-c -*-
2
 * dtlk.c - DoubleTalk PC driver for Linux
3
 *
4
 * Original author: Chris Pallotta <chris@allmedia.com>
5
 * Current maintainer: Jim Van Zandt <jrv@vanzandt.mv.com>
6
 *
7
 * 2000-03-18 Jim Van Zandt: Fix polling.
8
 *  Eliminate dtlk_timer_active flag and separate dtlk_stop_timer
9
 *  function.  Don't restart timer in dtlk_timer_tick.  Restart timer
10
 *  in dtlk_poll after every poll.  dtlk_poll returns mask (duh).
11
 *  Eliminate unused function dtlk_write_byte.  Misc. code cleanups.
12
 */
13
 
14
/* This driver is for the DoubleTalk PC, a speech synthesizer
15
   manufactured by RC Systems (http://www.rcsys.com/).  It was written
16
   based on documentation in their User's Manual file and Developer's
17
   Tools disk.
18
 
19
   The DoubleTalk PC contains four voice synthesizers: text-to-speech
20
   (TTS), linear predictive coding (LPC), PCM/ADPCM, and CVSD.  It
21
   also has a tone generator.  Output data for LPC are written to the
22
   LPC port, and output data for the other modes are written to the
23
   TTS port.
24
 
25
   Two kinds of data can be read from the DoubleTalk: status
26
   information (in response to the "\001?" interrogation command) is
27
   read from the TTS port, and index markers (which mark the progress
28
   of the speech) are read from the LPC port.  Not all models of the
29
   DoubleTalk PC implement index markers.  Both the TTS and LPC ports
30
   can also display status flags.
31
 
32
   The DoubleTalk PC generates no interrupts.
33
 
34
   These characteristics are mapped into the Unix stream I/O model as
35
   follows:
36
 
37
   "write" sends bytes to the TTS port.  It is the responsibility of
38
   the user program to switch modes among TTS, PCM/ADPCM, and CVSD.
39
   This driver was written for use with the text-to-speech
40
   synthesizer.  If LPC output is needed some day, other minor device
41
   numbers can be used to select among output modes.
42
 
43
   "read" gets index markers from the LPC port.  If the device does
44
   not implement index markers, the read will fail with error EINVAL.
45
 
46
   Status information is available using the DTLK_INTERROGATE ioctl.
47
 
48
 */
49
 
50
#include <linux/module.h>
51
 
52
#define KERNEL
53
#include <linux/types.h>
54
#include <linux/fs.h>
55
#include <linux/mm.h>
56
#include <linux/errno.h>        /* for -EBUSY */
57
#include <linux/ioport.h>       /* for request_region */
58
#include <linux/delay.h>        /* for loops_per_jiffy */
59
#include <asm/io.h>             /* for inb_p, outb_p, inb, outb, etc. */
60
#include <asm/uaccess.h>        /* for get_user, etc. */
61
#include <linux/wait.h>         /* for wait_queue */
62
#include <linux/init.h>         /* for __init, module_{init,exit} */
63
#include <linux/poll.h>         /* for POLLIN, etc. */
64
#include <linux/dtlk.h>         /* local header file for DoubleTalk values */
65
 
66
#ifdef TRACING
67
#define TRACE_TEXT(str) printk(str);
68
#define TRACE_RET printk(")")
69
#else                           /* !TRACING */
70
#define TRACE_TEXT(str) ((void) 0)
71
#define TRACE_RET ((void) 0)
72
#endif                          /* TRACING */
73
 
74
static void dtlk_timer_tick(unsigned long data);
75
 
76
static int dtlk_major;
77
static int dtlk_port_lpc;
78
static int dtlk_port_tts;
79
static int dtlk_busy;
80
static int dtlk_has_indexing;
81
static unsigned int dtlk_portlist[] =
82
{0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0};
83
static wait_queue_head_t dtlk_process_list;
84
static DEFINE_TIMER(dtlk_timer, dtlk_timer_tick, 0, 0);
85
 
86
/* prototypes for file_operations struct */
87
static ssize_t dtlk_read(struct file *, char __user *,
88
                         size_t nbytes, loff_t * ppos);
89
static ssize_t dtlk_write(struct file *, const char __user *,
90
                          size_t nbytes, loff_t * ppos);
91
static unsigned int dtlk_poll(struct file *, poll_table *);
92
static int dtlk_open(struct inode *, struct file *);
93
static int dtlk_release(struct inode *, struct file *);
94
static int dtlk_ioctl(struct inode *inode, struct file *file,
95
                      unsigned int cmd, unsigned long arg);
96
 
97
static const struct file_operations dtlk_fops =
98
{
99
        .owner          = THIS_MODULE,
100
        .read           = dtlk_read,
101
        .write          = dtlk_write,
102
        .poll           = dtlk_poll,
103
        .ioctl          = dtlk_ioctl,
104
        .open           = dtlk_open,
105
        .release        = dtlk_release,
106
};
107
 
108
/* local prototypes */
109
static int dtlk_dev_probe(void);
110
static struct dtlk_settings *dtlk_interrogate(void);
111
static int dtlk_readable(void);
112
static char dtlk_read_lpc(void);
113
static char dtlk_read_tts(void);
114
static int dtlk_writeable(void);
115
static char dtlk_write_bytes(const char *buf, int n);
116
static char dtlk_write_tts(char);
117
/*
118
   static void dtlk_handle_error(char, char, unsigned int);
119
 */
120
 
121
static ssize_t dtlk_read(struct file *file, char __user *buf,
122
                         size_t count, loff_t * ppos)
123
{
124
        unsigned int minor = iminor(file->f_path.dentry->d_inode);
125
        char ch;
126
        int i = 0, retries;
127
 
128
        TRACE_TEXT("(dtlk_read");
129
        /*  printk("DoubleTalk PC - dtlk_read()\n"); */
130
 
131
        if (minor != DTLK_MINOR || !dtlk_has_indexing)
132
                return -EINVAL;
133
 
134
        for (retries = 0; retries < loops_per_jiffy; retries++) {
135
                while (i < count && dtlk_readable()) {
136
                        ch = dtlk_read_lpc();
137
                        /*        printk("dtlk_read() reads 0x%02x\n", ch); */
138
                        if (put_user(ch, buf++))
139
                                return -EFAULT;
140
                        i++;
141
                }
142
                if (i)
143
                        return i;
144
                if (file->f_flags & O_NONBLOCK)
145
                        break;
146
                msleep_interruptible(100);
147
        }
148
        if (retries == loops_per_jiffy)
149
                printk(KERN_ERR "dtlk_read times out\n");
150
        TRACE_RET;
151
        return -EAGAIN;
152
}
153
 
154
static ssize_t dtlk_write(struct file *file, const char __user *buf,
155
                          size_t count, loff_t * ppos)
156
{
157
        int i = 0, retries = 0, ch;
158
 
159
        TRACE_TEXT("(dtlk_write");
160
#ifdef TRACING
161
        printk(" \"");
162
        {
163
                int i, ch;
164
                for (i = 0; i < count; i++) {
165
                        if (get_user(ch, buf + i))
166
                                return -EFAULT;
167
                        if (' ' <= ch && ch <= '~')
168
                                printk("%c", ch);
169
                        else
170
                                printk("\\%03o", ch);
171
                }
172
                printk("\"");
173
        }
174
#endif
175
 
176
        if (iminor(file->f_path.dentry->d_inode) != DTLK_MINOR)
177
                return -EINVAL;
178
 
179
        while (1) {
180
                while (i < count && !get_user(ch, buf) &&
181
                       (ch == DTLK_CLEAR || dtlk_writeable())) {
182
                        dtlk_write_tts(ch);
183
                        buf++;
184
                        i++;
185
                        if (i % 5 == 0)
186
                                /* We yield our time until scheduled
187
                                   again.  This reduces the transfer
188
                                   rate to 500 bytes/sec, but that's
189
                                   still enough to keep up with the
190
                                   speech synthesizer. */
191
                                msleep_interruptible(1);
192
                        else {
193
                                /* the RDY bit goes zero 2-3 usec
194
                                   after writing, and goes 1 again
195
                                   180-190 usec later.  Here, we wait
196
                                   up to 250 usec for the RDY bit to
197
                                   go nonzero. */
198
                                for (retries = 0;
199
                                     retries < loops_per_jiffy / (4000/HZ);
200
                                     retries++)
201
                                        if (inb_p(dtlk_port_tts) &
202
                                            TTS_WRITABLE)
203
                                                break;
204
                        }
205
                        retries = 0;
206
                }
207
                if (i == count)
208
                        return i;
209
                if (file->f_flags & O_NONBLOCK)
210
                        break;
211
 
212
                msleep_interruptible(1);
213
 
214
                if (++retries > 10 * HZ) { /* wait no more than 10 sec
215
                                              from last write */
216
                        printk("dtlk: write timeout.  "
217
                               "inb_p(dtlk_port_tts) = 0x%02x\n",
218
                               inb_p(dtlk_port_tts));
219
                        TRACE_RET;
220
                        return -EBUSY;
221
                }
222
        }
223
        TRACE_RET;
224
        return -EAGAIN;
225
}
226
 
227
static unsigned int dtlk_poll(struct file *file, poll_table * wait)
228
{
229
        int mask = 0;
230
        unsigned long expires;
231
 
232
        TRACE_TEXT(" dtlk_poll");
233
        /*
234
           static long int j;
235
           printk(".");
236
           printk("<%ld>", jiffies-j);
237
           j=jiffies;
238
         */
239
        poll_wait(file, &dtlk_process_list, wait);
240
 
241
        if (dtlk_has_indexing && dtlk_readable()) {
242
                del_timer(&dtlk_timer);
243
                mask = POLLIN | POLLRDNORM;
244
        }
245
        if (dtlk_writeable()) {
246
                del_timer(&dtlk_timer);
247
                mask |= POLLOUT | POLLWRNORM;
248
        }
249
        /* there are no exception conditions */
250
 
251
        /* There won't be any interrupts, so we set a timer instead. */
252
        expires = jiffies + 3*HZ / 100;
253
        mod_timer(&dtlk_timer, expires);
254
 
255
        return mask;
256
}
257
 
258
static void dtlk_timer_tick(unsigned long data)
259
{
260
        TRACE_TEXT(" dtlk_timer_tick");
261
        wake_up_interruptible(&dtlk_process_list);
262
}
263
 
264
static int dtlk_ioctl(struct inode *inode,
265
                      struct file *file,
266
                      unsigned int cmd,
267
                      unsigned long arg)
268
{
269
        char __user *argp = (char __user *)arg;
270
        struct dtlk_settings *sp;
271
        char portval;
272
        TRACE_TEXT(" dtlk_ioctl");
273
 
274
        switch (cmd) {
275
 
276
        case DTLK_INTERROGATE:
277
                sp = dtlk_interrogate();
278
                if (copy_to_user(argp, sp, sizeof(struct dtlk_settings)))
279
                        return -EINVAL;
280
                return 0;
281
 
282
        case DTLK_STATUS:
283
                portval = inb_p(dtlk_port_tts);
284
                return put_user(portval, argp);
285
 
286
        default:
287
                return -EINVAL;
288
        }
289
}
290
 
291
static int dtlk_open(struct inode *inode, struct file *file)
292
{
293
        TRACE_TEXT("(dtlk_open");
294
 
295
        nonseekable_open(inode, file);
296
        switch (iminor(inode)) {
297
        case DTLK_MINOR:
298
                if (dtlk_busy)
299
                        return -EBUSY;
300
                return nonseekable_open(inode, file);
301
 
302
        default:
303
                return -ENXIO;
304
        }
305
}
306
 
307
static int dtlk_release(struct inode *inode, struct file *file)
308
{
309
        TRACE_TEXT("(dtlk_release");
310
 
311
        switch (iminor(inode)) {
312
        case DTLK_MINOR:
313
                break;
314
 
315
        default:
316
                break;
317
        }
318
        TRACE_RET;
319
 
320
        del_timer_sync(&dtlk_timer);
321
 
322
        return 0;
323
}
324
 
325
static int __init dtlk_init(void)
326
{
327
        int err;
328
 
329
        dtlk_port_lpc = 0;
330
        dtlk_port_tts = 0;
331
        dtlk_busy = 0;
332
        dtlk_major = register_chrdev(0, "dtlk", &dtlk_fops);
333
        if (dtlk_major < 0) {
334
                printk(KERN_ERR "DoubleTalk PC - cannot register device\n");
335
                return dtlk_major;
336
        }
337
        err = dtlk_dev_probe();
338
        if (err) {
339
                unregister_chrdev(dtlk_major, "dtlk");
340
                return err;
341
        }
342
        printk(", MAJOR %d\n", dtlk_major);
343
 
344
        init_waitqueue_head(&dtlk_process_list);
345
 
346
        return 0;
347
}
348
 
349
static void __exit dtlk_cleanup (void)
350
{
351
        dtlk_write_bytes("goodbye", 8);
352
        msleep_interruptible(500);              /* nap 0.50 sec but
353
                                                   could be awakened
354
                                                   earlier by
355
                                                   signals... */
356
 
357
        dtlk_write_tts(DTLK_CLEAR);
358
        unregister_chrdev(dtlk_major, "dtlk");
359
        release_region(dtlk_port_lpc, DTLK_IO_EXTENT);
360
}
361
 
362
module_init(dtlk_init);
363
module_exit(dtlk_cleanup);
364
 
365
/* ------------------------------------------------------------------------ */
366
 
367
static int dtlk_readable(void)
368
{
369
#ifdef TRACING
370
        printk(" dtlk_readable=%u@%u", inb_p(dtlk_port_lpc) != 0x7f, jiffies);
371
#endif
372
        return inb_p(dtlk_port_lpc) != 0x7f;
373
}
374
 
375
static int dtlk_writeable(void)
376
{
377
        /* TRACE_TEXT(" dtlk_writeable"); */
378
#ifdef TRACINGMORE
379
        printk(" dtlk_writeable=%u", (inb_p(dtlk_port_tts) & TTS_WRITABLE)!=0);
380
#endif
381
        return inb_p(dtlk_port_tts) & TTS_WRITABLE;
382
}
383
 
384
static int __init dtlk_dev_probe(void)
385
{
386
        unsigned int testval = 0;
387
        int i = 0;
388
        struct dtlk_settings *sp;
389
 
390
        if (dtlk_port_lpc | dtlk_port_tts)
391
                return -EBUSY;
392
 
393
        for (i = 0; dtlk_portlist[i]; i++) {
394
#if 0
395
                printk("DoubleTalk PC - Port %03x = %04x\n",
396
                       dtlk_portlist[i], (testval = inw_p(dtlk_portlist[i])));
397
#endif
398
 
399
                if (!request_region(dtlk_portlist[i], DTLK_IO_EXTENT,
400
                               "dtlk"))
401
                        continue;
402
                testval = inw_p(dtlk_portlist[i]);
403
                if ((testval &= 0xfbff) == 0x107f) {
404
                        dtlk_port_lpc = dtlk_portlist[i];
405
                        dtlk_port_tts = dtlk_port_lpc + 1;
406
 
407
                        sp = dtlk_interrogate();
408
                        printk("DoubleTalk PC at %03x-%03x, "
409
                               "ROM version %s, serial number %u",
410
                               dtlk_portlist[i], dtlk_portlist[i] +
411
                               DTLK_IO_EXTENT - 1,
412
                               sp->rom_version, sp->serial_number);
413
 
414
                        /* put LPC port into known state, so
415
                           dtlk_readable() gives valid result */
416
                        outb_p(0xff, dtlk_port_lpc);
417
 
418
                        /* INIT string and index marker */
419
                        dtlk_write_bytes("\036\1@\0\0012I\r", 8);
420
                        /* posting an index takes 18 msec.  Here, we
421
                           wait up to 100 msec to see whether it
422
                           appears. */
423
                        msleep_interruptible(100);
424
                        dtlk_has_indexing = dtlk_readable();
425
#ifdef TRACING
426
                        printk(", indexing %d\n", dtlk_has_indexing);
427
#endif
428
#ifdef INSCOPE
429
                        {
430
/* This macro records ten samples read from the LPC port, for later display */
431
#define LOOK                                    \
432
for (i = 0; i < 10; i++)                 \
433
  {                                             \
434
    buffer[b++] = inb_p(dtlk_port_lpc);         \
435
    __delay(loops_per_jiffy/(1000000/HZ));             \
436
  }
437
                                char buffer[1000];
438
                                int b = 0, i, j;
439
 
440
                                LOOK
441
                                outb_p(0xff, dtlk_port_lpc);
442
                                buffer[b++] = 0;
443
                                LOOK
444
                                dtlk_write_bytes("\0012I\r", 4);
445
                                buffer[b++] = 0;
446
                                __delay(50 * loops_per_jiffy / (1000/HZ));
447
                                outb_p(0xff, dtlk_port_lpc);
448
                                buffer[b++] = 0;
449
                                LOOK
450
 
451
                                printk("\n");
452
                                for (j = 0; j < b; j++)
453
                                        printk(" %02x", buffer[j]);
454
                                printk("\n");
455
                        }
456
#endif                          /* INSCOPE */
457
 
458
#ifdef OUTSCOPE
459
                        {
460
/* This macro records ten samples read from the TTS port, for later display */
461
#define LOOK                                    \
462
for (i = 0; i < 10; i++)                 \
463
  {                                             \
464
    buffer[b++] = inb_p(dtlk_port_tts);         \
465
    __delay(loops_per_jiffy/(1000000/HZ));  /* 1 us */ \
466
  }
467
                                char buffer[1000];
468
                                int b = 0, i, j;
469
 
470
                                mdelay(10);     /* 10 ms */
471
                                LOOK
472
                                outb_p(0x03, dtlk_port_tts);
473
                                buffer[b++] = 0;
474
                                LOOK
475
                                LOOK
476
 
477
                                printk("\n");
478
                                for (j = 0; j < b; j++)
479
                                        printk(" %02x", buffer[j]);
480
                                printk("\n");
481
                        }
482
#endif                          /* OUTSCOPE */
483
 
484
                        dtlk_write_bytes("Double Talk found", 18);
485
 
486
                        return 0;
487
                }
488
                release_region(dtlk_portlist[i], DTLK_IO_EXTENT);
489
        }
490
 
491
        printk(KERN_INFO "DoubleTalk PC - not found\n");
492
        return -ENODEV;
493
}
494
 
495
/*
496
   static void dtlk_handle_error(char op, char rc, unsigned int minor)
497
   {
498
   printk(KERN_INFO"\nDoubleTalk PC - MINOR: %d, OPCODE: %d, ERROR: %d\n",
499
   minor, op, rc);
500
   return;
501
   }
502
 */
503
 
504
/* interrogate the DoubleTalk PC and return its settings */
505
static struct dtlk_settings *dtlk_interrogate(void)
506
{
507
        unsigned char *t;
508
        static char buf[sizeof(struct dtlk_settings) + 1];
509
        int total, i;
510
        static struct dtlk_settings status;
511
        TRACE_TEXT("(dtlk_interrogate");
512
        dtlk_write_bytes("\030\001?", 3);
513
        for (total = 0, i = 0; i < 50; i++) {
514
                buf[total] = dtlk_read_tts();
515
                if (total > 2 && buf[total] == 0x7f)
516
                        break;
517
                if (total < sizeof(struct dtlk_settings))
518
                        total++;
519
        }
520
        /*
521
           if (i==50) printk("interrogate() read overrun\n");
522
           for (i=0; i<sizeof(buf); i++)
523
           printk(" %02x", buf[i]);
524
           printk("\n");
525
         */
526
        t = buf;
527
        status.serial_number = t[0] + t[1] * 256; /* serial number is
528
                                                     little endian */
529
        t += 2;
530
 
531
        i = 0;
532
        while (*t != '\r') {
533
                status.rom_version[i] = *t;
534
                if (i < sizeof(status.rom_version) - 1)
535
                        i++;
536
                t++;
537
        }
538
        status.rom_version[i] = 0;
539
        t++;
540
 
541
        status.mode = *t++;
542
        status.punc_level = *t++;
543
        status.formant_freq = *t++;
544
        status.pitch = *t++;
545
        status.speed = *t++;
546
        status.volume = *t++;
547
        status.tone = *t++;
548
        status.expression = *t++;
549
        status.ext_dict_loaded = *t++;
550
        status.ext_dict_status = *t++;
551
        status.free_ram = *t++;
552
        status.articulation = *t++;
553
        status.reverb = *t++;
554
        status.eob = *t++;
555
        status.has_indexing = dtlk_has_indexing;
556
        TRACE_RET;
557
        return &status;
558
}
559
 
560
static char dtlk_read_tts(void)
561
{
562
        int portval, retries = 0;
563
        char ch;
564
        TRACE_TEXT("(dtlk_read_tts");
565
 
566
        /* verify DT is ready, read char, wait for ACK */
567
        do {
568
                portval = inb_p(dtlk_port_tts);
569
        } while ((portval & TTS_READABLE) == 0 &&
570
                 retries++ < DTLK_MAX_RETRIES);
571
        if (retries == DTLK_MAX_RETRIES)
572
                printk(KERN_ERR "dtlk_read_tts() timeout\n");
573
 
574
        ch = inb_p(dtlk_port_tts);      /* input from TTS port */
575
        ch &= 0x7f;
576
        outb_p(ch, dtlk_port_tts);
577
 
578
        retries = 0;
579
        do {
580
                portval = inb_p(dtlk_port_tts);
581
        } while ((portval & TTS_READABLE) != 0 &&
582
                 retries++ < DTLK_MAX_RETRIES);
583
        if (retries == DTLK_MAX_RETRIES)
584
                printk(KERN_ERR "dtlk_read_tts() timeout\n");
585
 
586
        TRACE_RET;
587
        return ch;
588
}
589
 
590
static char dtlk_read_lpc(void)
591
{
592
        int retries = 0;
593
        char ch;
594
        TRACE_TEXT("(dtlk_read_lpc");
595
 
596
        /* no need to test -- this is only called when the port is readable */
597
 
598
        ch = inb_p(dtlk_port_lpc);      /* input from LPC port */
599
 
600
        outb_p(0xff, dtlk_port_lpc);
601
 
602
        /* acknowledging a read takes 3-4
603
           usec.  Here, we wait up to 20 usec
604
           for the acknowledgement */
605
        retries = (loops_per_jiffy * 20) / (1000000/HZ);
606
        while (inb_p(dtlk_port_lpc) != 0x7f && --retries > 0);
607
        if (retries == 0)
608
                printk(KERN_ERR "dtlk_read_lpc() timeout\n");
609
 
610
        TRACE_RET;
611
        return ch;
612
}
613
 
614
/* write n bytes to tts port */
615
static char dtlk_write_bytes(const char *buf, int n)
616
{
617
        char val = 0;
618
        /*  printk("dtlk_write_bytes(\"%-*s\", %d)\n", n, buf, n); */
619
        TRACE_TEXT("(dtlk_write_bytes");
620
        while (n-- > 0)
621
                val = dtlk_write_tts(*buf++);
622
        TRACE_RET;
623
        return val;
624
}
625
 
626
static char dtlk_write_tts(char ch)
627
{
628
        int retries = 0;
629
#ifdef TRACINGMORE
630
        printk("  dtlk_write_tts(");
631
        if (' ' <= ch && ch <= '~')
632
                printk("'%c'", ch);
633
        else
634
                printk("0x%02x", ch);
635
#endif
636
        if (ch != DTLK_CLEAR)   /* no flow control for CLEAR command */
637
                while ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0 &&
638
                       retries++ < DTLK_MAX_RETRIES)    /* DT ready? */
639
                        ;
640
        if (retries == DTLK_MAX_RETRIES)
641
                printk(KERN_ERR "dtlk_write_tts() timeout\n");
642
 
643
        outb_p(ch, dtlk_port_tts);      /* output to TTS port */
644
        /* the RDY bit goes zero 2-3 usec after writing, and goes
645
           1 again 180-190 usec later.  Here, we wait up to 10
646
           usec for the RDY bit to go zero. */
647
        for (retries = 0; retries < loops_per_jiffy / (100000/HZ); retries++)
648
                if ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0)
649
                        break;
650
 
651
#ifdef TRACINGMORE
652
        printk(")\n");
653
#endif
654
        return 0;
655
}
656
 
657
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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