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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [mips/] [kernel/] [gdb-stub.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1624 jcastillo
/*
2
 *  arch/mips/kernel/gdb-stub.c
3
 *
4
 *  Originally written by Glenn Engel, Lake Stevens Instrument Division
5
 *
6
 *  Contributed by HP Systems
7
 *
8
 *  Modified for SPARC by Stu Grossman, Cygnus Support.
9
 *
10
 *  Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
11
 *  Send complaints, suggestions etc. to <andy@waldorf-gmbh.de>
12
 *
13
 *  Copyright (C) 1995 Andreas Busse
14
 */
15
 
16
/*
17
 *  To enable debugger support, two things need to happen.  One, a
18
 *  call to set_debug_traps() is necessary in order to allow any breakpoints
19
 *  or error conditions to be properly intercepted and reported to gdb.
20
 *  Two, a breakpoint needs to be generated to begin communication.  This
21
 *  is most easily accomplished by a call to breakpoint().  Breakpoint()
22
 *  simulates a breakpoint by executing a BREAK instruction.
23
 *
24
 *
25
 *    The following gdb commands are supported:
26
 *
27
 * command          function                               Return value
28
 *
29
 *    g             return the value of the CPU registers  hex data or ENN
30
 *    G             set the value of the CPU registers     OK or ENN
31
 *
32
 *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
33
 *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
34
 *
35
 *    c             Resume at current address              SNN   ( signal NN)
36
 *    cAA..AA       Continue at address AA..AA             SNN
37
 *
38
 *    s             Step one instruction                   SNN
39
 *    sAA..AA       Step one instruction from AA..AA       SNN
40
 *
41
 *    k             kill
42
 *
43
 *    ?             What was the last sigval ?             SNN   (signal NN)
44
 *
45
 *    bBB..BB       Set baud rate to BB..BB                OK or BNN, then sets
46
 *                                                         baud rate
47
 *
48
 * All commands and responses are sent with a packet which includes a
49
 * checksum.  A packet consists of
50
 *
51
 * $<packet info>#<checksum>.
52
 *
53
 * where
54
 * <packet info> :: <characters representing the command or response>
55
 * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
56
 *
57
 * When a packet is received, it is first acknowledged with either '+' or '-'.
58
 * '+' indicates a successful transfer.  '-' indicates a failed transfer.
59
 *
60
 * Example:
61
 *
62
 * Host:                  Reply:
63
 * $m0,10#2a               +$00010203040506070809101112131415#42
64
 *
65
 */
66
 
67
#include <linux/string.h>
68
#include <linux/signal.h>
69
#include <linux/kernel.h>
70
 
71
#include <asm/asm.h>
72
#include <asm/mipsregs.h>
73
#include <asm/segment.h>
74
#include <asm/cachectl.h>
75
#include <asm/system.h>
76
#include <asm/gdb-stub.h>
77
 
78
/*
79
 * external low-level support routines
80
 */
81
 
82
extern int putDebugChar(char c);    /* write a single character      */
83
extern char getDebugChar(void);     /* read and return a single char */
84
extern void fltr_set_mem_err(void);
85
extern void trap_low(void);
86
 
87
/*
88
 * breakpoint and test functions
89
 */
90
extern void breakpoint(void);
91
extern void breakinst(void);
92
extern void adel(void);
93
 
94
/*
95
 * local prototypes
96
 */
97
 
98
static void getpacket(char *buffer);
99
static void putpacket(char *buffer);
100
static void set_mem_fault_trap(int enable);
101
static int computeSignal(int tt);
102
static int hex(unsigned char ch);
103
static int hexToInt(char **ptr, int *intValue);
104
static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault);
105
void handle_exception(struct gdb_regs *regs);
106
static void show_gdbregs(struct gdb_regs *regs);
107
 
108
/*
109
 * BUFMAX defines the maximum number of characters in inbound/outbound buffers
110
 * at least NUMREGBYTES*2 are needed for register packets
111
 */
112
#define BUFMAX 2048
113
 
114
static char input_buffer[BUFMAX];
115
static char output_buffer[BUFMAX];
116
static int initialized = 0;      /* !0 means we've been initialized */
117
static const char hexchars[]="0123456789abcdef";
118
 
119
 
120
/*
121
 * Convert ch from a hex digit to an int
122
 */
123
static int hex(unsigned char ch)
124
{
125
        if (ch >= 'a' && ch <= 'f')
126
                return ch-'a'+10;
127
        if (ch >= '0' && ch <= '9')
128
                return ch-'0';
129
        if (ch >= 'A' && ch <= 'F')
130
                return ch-'A'+10;
131
        return -1;
132
}
133
 
134
/*
135
 * scan for the sequence $<data>#<checksum>
136
 */
137
static void getpacket(char *buffer)
138
{
139
        unsigned char checksum;
140
        unsigned char xmitcsum;
141
        int i;
142
        int count;
143
        unsigned char ch;
144
 
145
        do {
146
                /*
147
                 * wait around for the start character,
148
                 * ignore all other characters
149
                 */
150
                while ((ch = (getDebugChar() & 0x7f)) != '$') ;
151
 
152
                checksum = 0;
153
                xmitcsum = -1;
154
                count = 0;
155
 
156
                /*
157
                 * now, read until a # or end of buffer is found
158
                 */
159
                while (count < BUFMAX) {
160
                        ch = getDebugChar() & 0x7f;
161
                        if (ch == '#')
162
                                break;
163
                        checksum = checksum + ch;
164
                        buffer[count] = ch;
165
                        count = count + 1;
166
                }
167
 
168
                if (count >= BUFMAX)
169
                        continue;
170
 
171
                buffer[count] = 0;
172
 
173
                if (ch == '#') {
174
                        xmitcsum = hex(getDebugChar() & 0x7f) << 4;
175
                        xmitcsum |= hex(getDebugChar() & 0x7f);
176
 
177
                        if (checksum != xmitcsum)
178
                                putDebugChar('-');      /* failed checksum */
179
                        else {
180
                                putDebugChar('+'); /* successful transfer */
181
 
182
                                /*
183
                                 * if a sequence char is present,
184
                                 * reply the sequence ID
185
                                 */
186
                                if (buffer[2] == ':') {
187
                                        putDebugChar(buffer[0]);
188
                                        putDebugChar(buffer[1]);
189
 
190
                                        /*
191
                                         * remove sequence chars from buffer
192
                                         */
193
                                        count = strlen(buffer);
194
                                        for (i=3; i <= count; i++)
195
                                                buffer[i-3] = buffer[i];
196
                                }
197
                        }
198
                }
199
        }
200
        while (checksum != xmitcsum);
201
}
202
 
203
/*
204
 * send the packet in buffer.
205
 */
206
static void putpacket(char *buffer)
207
{
208
        unsigned char checksum;
209
        int count;
210
        unsigned char ch;
211
 
212
        /*
213
         * $<packet info>#<checksum>.
214
         */
215
 
216
        do {
217
                putDebugChar('$');
218
                checksum = 0;
219
                count = 0;
220
 
221
                while ((ch = buffer[count]) != 0) {
222
                        if (!(putDebugChar(ch)))
223
                                return;
224
                        checksum += ch;
225
                        count += 1;
226
                }
227
 
228
                putDebugChar('#');
229
                putDebugChar(hexchars[checksum >> 4]);
230
                putDebugChar(hexchars[checksum & 0xf]);
231
 
232
        }
233
        while ((getDebugChar() & 0x7f) != '+');
234
}
235
 
236
 
237
/*
238
 * Indicate to caller of mem2hex or hex2mem that there
239
 * has been an error.
240
 */
241
static volatile int mem_err = 0;
242
 
243
/*
244
 * Convert the memory pointed to by mem into hex, placing result in buf.
245
 * Return a pointer to the last char put in buf (null), in case of mem fault,
246
 * return 0.
247
 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
248
 * a 0, else treat a fault like any other fault in the stub.
249
 */
250
static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault)
251
{
252
        unsigned char ch;
253
 
254
/*      set_mem_fault_trap(may_fault); */
255
 
256
        while (count-- > 0) {
257
                ch = *(mem++);
258
                if (mem_err)
259
                        return 0;
260
                *buf++ = hexchars[ch >> 4];
261
                *buf++ = hexchars[ch & 0xf];
262
        }
263
 
264
        *buf = 0;
265
 
266
/*      set_mem_fault_trap(0); */
267
 
268
        return buf;
269
}
270
 
271
/*
272
 * convert the hex array pointed to by buf into binary to be placed in mem
273
 * return a pointer to the character AFTER the last byte written
274
 */
275
static char *hex2mem(char *buf, char *mem, int count, int may_fault)
276
{
277
        int i;
278
        unsigned char ch;
279
 
280
/*      set_mem_fault_trap(may_fault); */
281
 
282
        for (i=0; i<count; i++)
283
        {
284
                ch = hex(*buf++) << 4;
285
                ch |= hex(*buf++);
286
                *(mem++) = ch;
287
                if (mem_err)
288
                        return 0;
289
        }
290
 
291
/*      set_mem_fault_trap(0); */
292
 
293
        return mem;
294
}
295
 
296
/*
297
 * This table contains the mapping between SPARC hardware trap types, and
298
 * signals, which are primarily what GDB understands.  It also indicates
299
 * which hardware traps we need to commandeer when initializing the stub.
300
 */
301
static struct hard_trap_info
302
{
303
        unsigned char tt;               /* Trap type code for MIPS R3xxx and R4xxx */
304
        unsigned char signo;            /* Signal that we map this trap into */
305
} hard_trap_info[] = {
306
        { 4, SIGBUS },                  /* address error (load) */
307
        { 5, SIGBUS },                  /* address error (store) */
308
        { 6, SIGBUS },                  /* instruction bus error */
309
        { 7, SIGBUS },                  /* data bus error */
310
        { 9, SIGTRAP },                 /* break */
311
        { 10, SIGILL },                 /* reserved instruction */
312
/*      { 11, SIGILL },         */      /* cpu unusable */
313
        { 12, SIGFPE },                 /* overflow */
314
        { 13, SIGTRAP },                /* trap */
315
        { 14, SIGSEGV },                /* virtual instruction cache coherency */
316
        { 15, SIGFPE },                 /* floating point exception */
317
        { 23, SIGSEGV },                /* watch */
318
        { 31, SIGSEGV },                /* virtual data cache coherency */
319
        { 0, 0}                           /* Must be last */
320
};
321
 
322
 
323
/*
324
 * Set up exception handlers for tracing and breakpoints
325
 */
326
void set_debug_traps(void)
327
{
328
        struct hard_trap_info *ht;
329
 
330
        for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
331
                set_except_vector(ht->tt, trap_low);
332
 
333
        /*
334
         * In case GDB is started before us, ack any packets
335
         * (presumably "$?#xx") sitting there.
336
         */
337
 
338
        putDebugChar ('+');
339
        initialized = 1;
340
 
341
        breakpoint();
342
}
343
 
344
 
345
/*
346
 * Trap handler for memory errors.  This just sets mem_err to be non-zero.  It
347
 * assumes that %l1 is non-zero.  This should be safe, as it is doubtful that
348
 * 0 would ever contain code that could mem fault.  This routine will skip
349
 * past the faulting instruction after setting mem_err.
350
 */
351
extern void fltr_set_mem_err(void)
352
{
353
  /* FIXME: Needs to be written... */
354
}
355
 
356
 
357
static void set_mem_fault_trap(int enable)
358
{
359
  mem_err = 0;
360
 
361
#if 0
362
  if (enable)
363
    exceptionHandler(9, fltr_set_mem_err);
364
  else
365
    exceptionHandler(9, trap_low);
366
#endif  
367
}
368
 
369
/*
370
 * Convert the MIPS hardware trap type code to a unix signal number.
371
 */
372
static int computeSignal(int tt)
373
{
374
        struct hard_trap_info *ht;
375
 
376
        for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
377
                if (ht->tt == tt)
378
                        return ht->signo;
379
 
380
        return SIGHUP;          /* default for things we don't know about */
381
}
382
 
383
/*
384
 * While we find nice hex chars, build an int.
385
 * Return number of chars processed.
386
 */
387
static int hexToInt(char **ptr, int *intValue)
388
{
389
        int numChars = 0;
390
        int hexValue;
391
 
392
        *intValue = 0;
393
 
394
        while (**ptr)
395
        {
396
                hexValue = hex(**ptr);
397
                if (hexValue < 0)
398
                        break;
399
 
400
                *intValue = (*intValue << 4) | hexValue;
401
                numChars ++;
402
 
403
                (*ptr)++;
404
        }
405
 
406
        return (numChars);
407
}
408
 
409
/*
410
 * This function does all command processing for interfacing to gdb.  It
411
 * returns 1 if you should skip the instruction at the trap address, 0
412
 * otherwise.
413
 */
414
void handle_exception (struct gdb_regs *regs)
415
{
416
        int trap;                       /* Trap type */
417
        int sigval;
418
        int addr;
419
        int length;
420
        char *ptr;
421
        unsigned long *stack;
422
 
423
#if 0   
424
        printk("in handle_exception()\n");
425
        show_gdbregs(regs);
426
#endif
427
 
428
        /*
429
         * First check trap type. If this is CPU_UNUSABLE and CPU_ID is 1,
430
         * the simply switch the FPU on and return since this is no error
431
         * condition. kernel/traps.c does the same.
432
         * FIXME: This doesn't work yet, so we don't catch CPU_UNUSABLE
433
         * traps for now.
434
         */
435
        trap = (regs->cp0_cause & 0x7c) >> 2;
436
/*      printk("trap=%d\n",trap); */
437
        if (trap == 11) {
438
                if (((regs->cp0_cause >> CAUSEB_CE) & 3) == 1) {
439
                        regs->cp0_status |= ST0_CU1;
440
                        return;
441
                }
442
        }
443
 
444
        /*
445
         * If we're in breakpoint() increment the PC
446
         */
447
        if (trap == 9 && regs->cp0_epc == (unsigned long)breakinst)
448
                regs->cp0_epc += 4;
449
 
450
        stack = (long *)regs->reg29;                    /* stack ptr */
451
        sigval = computeSignal(trap);
452
 
453
        /*
454
         * reply to host that an exception has occurred
455
         */
456
        ptr = output_buffer;
457
 
458
        /*
459
         * Send trap type (converted to signal)
460
         */
461
        *ptr++ = 'T';
462
        *ptr++ = hexchars[sigval >> 4];
463
        *ptr++ = hexchars[sigval & 0xf];
464
 
465
        /*
466
         * Send Error PC
467
         */
468
        *ptr++ = hexchars[REG_EPC >> 4];
469
        *ptr++ = hexchars[REG_EPC & 0xf];
470
        *ptr++ = ':';
471
        ptr = mem2hex((char *)&regs->cp0_epc, ptr, 4, 0);
472
        *ptr++ = ';';
473
 
474
        /*
475
         * Send frame pointer
476
         */
477
        *ptr++ = hexchars[REG_FP >> 4];
478
        *ptr++ = hexchars[REG_FP & 0xf];
479
        *ptr++ = ':';
480
        ptr = mem2hex((char *)&regs->reg30, ptr, 4, 0);
481
        *ptr++ = ';';
482
 
483
        /*
484
         * Send stack pointer
485
         */
486
        *ptr++ = hexchars[REG_SP >> 4];
487
        *ptr++ = hexchars[REG_SP & 0xf];
488
        *ptr++ = ':';
489
        ptr = mem2hex((char *)&regs->reg29, ptr, 4, 0);
490
        *ptr++ = ';';
491
 
492
        *ptr++ = 0;
493
        putpacket(output_buffer);       /* send it off... */
494
 
495
        /*
496
         * Wait for input from remote GDB
497
         */
498
        while (1) {
499
                output_buffer[0] = 0;
500
                getpacket(input_buffer);
501
 
502
                switch (input_buffer[0])
503
                {
504
                case '?':
505
                        output_buffer[0] = 'S';
506
                        output_buffer[1] = hexchars[sigval >> 4];
507
                        output_buffer[2] = hexchars[sigval & 0xf];
508
                        output_buffer[3] = 0;
509
                        break;
510
 
511
                case 'd':
512
                        /* toggle debug flag */
513
                        break;
514
 
515
                /*
516
                 * Return the value of the CPU registers
517
                 */
518
                case 'g':
519
                        ptr = output_buffer;
520
                        ptr = mem2hex((char *)&regs->reg0, ptr, 32*4, 0); /* r0...r31 */
521
                        ptr = mem2hex((char *)&regs->cp0_status, ptr, 6*4, 0); /* cp0 */
522
                        ptr = mem2hex((char *)&regs->fpr0, ptr, 32*4, 0); /* f0...31 */
523
                        ptr = mem2hex((char *)&regs->cp1_fsr, ptr, 2*4, 0); /* cp1 */
524
                        ptr = mem2hex((char *)&regs->frame_ptr, ptr, 2*4, 0); /* frp */
525
                        ptr = mem2hex((char *)&regs->cp0_index, ptr, 16*4, 0); /* cp0 */
526
                        break;
527
 
528
                /*
529
                 * set the value of the CPU registers - return OK
530
                 * FIXME: Needs to be written
531
                 */
532
                case 'G':
533
                {
534
#if 0
535
                        unsigned long *newsp, psr;
536
 
537
                        ptr = &input_buffer[1];
538
                        hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
539
 
540
                        /*
541
                         * See if the stack pointer has moved. If so, then copy the
542
                         * saved locals and ins to the new location.
543
                         */
544
 
545
                        newsp = (unsigned long *)registers[SP];
546
                        if (sp != newsp)
547
                                sp = memcpy(newsp, sp, 16 * 4);
548
 
549
#endif
550
                        strcpy(output_buffer,"OK");
551
                 }
552
                break;
553
 
554
                /*
555
                 * mAA..AA,LLLL  Read LLLL bytes at address AA..AA
556
                 */
557
                case 'm':
558
                        ptr = &input_buffer[1];
559
 
560
                        if (hexToInt(&ptr, &addr)
561
                                && *ptr++ == ','
562
                                && hexToInt(&ptr, &length)) {
563
                                if (mem2hex((char *)addr, output_buffer, length, 1))
564
                                        break;
565
                                strcpy (output_buffer, "E03");
566
                        } else
567
                                strcpy(output_buffer,"E01");
568
                        break;
569
 
570
                /*
571
                 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK
572
                 */
573
                case 'M':
574
                        ptr = &input_buffer[1];
575
 
576
                        if (hexToInt(&ptr, &addr)
577
                                && *ptr++ == ','
578
                                && hexToInt(&ptr, &length)
579
                                && *ptr++ == ':') {
580
                                if (hex2mem(ptr, (char *)addr, length, 1))
581
                                        strcpy(output_buffer, "OK");
582
                                else
583
                                        strcpy(output_buffer, "E03");
584
                        }
585
                        else
586
                                strcpy(output_buffer, "E02");
587
                        break;
588
 
589
                /*
590
                 * cAA..AA    Continue at address AA..AA(optional)
591
                 */
592
                case 'c':
593
                        /* try to read optional parameter, pc unchanged if no parm */
594
 
595
                        ptr = &input_buffer[1];
596
                        if (hexToInt(&ptr, &addr))
597
                                regs->cp0_epc = addr;
598
 
599
                        /*
600
                         * Need to flush the instruction cache here, as we may
601
                         * have deposited a breakpoint, and the icache probably
602
                         * has no way of knowing that a data ref to some location
603
                         * may have changed something that is in the instruction
604
                         * cache.
605
                         * NB: We flush both caches, just to be sure...
606
                         */
607
 
608
                        sys_cacheflush((void *)KSEG0,KSEG1-KSEG0,BCACHE);
609
                        return;
610
                        /* NOTREACHED */
611
                        break;
612
 
613
 
614
                /*
615
                 * kill the program
616
                 */
617
                case 'k' :
618
                        break;          /* do nothing */
619
 
620
 
621
                /*
622
                 * Reset the whole machine (FIXME: system dependent)
623
                 */
624
                case 'r':
625
                        break;
626
 
627
 
628
                /*
629
                 * Step to next instruction
630
                 * FIXME: Needs to be written
631
                 */
632
                case 's':
633
                        strcpy (output_buffer, "S01");
634
                        break;
635
 
636
                /*
637
                 * Set baud rate (bBB)
638
                 * FIXME: Needs to be written
639
                 */
640
                case 'b':
641
                {
642
#if 0                           
643
                        int baudrate;
644
                        extern void set_timer_3();
645
 
646
                        ptr = &input_buffer[1];
647
                        if (!hexToInt(&ptr, &baudrate))
648
                        {
649
                                strcpy(output_buffer,"B01");
650
                                break;
651
                        }
652
 
653
                        /* Convert baud rate to uart clock divider */
654
 
655
                        switch (baudrate)
656
                        {
657
                                case 38400:
658
                                        baudrate = 16;
659
                                        break;
660
                                case 19200:
661
                                        baudrate = 33;
662
                                        break;
663
                                case 9600:
664
                                        baudrate = 65;
665
                                        break;
666
                                default:
667
                                        baudrate = 0;
668
                                        strcpy(output_buffer,"B02");
669
                                        goto x1;
670
                        }
671
 
672
                        if (baudrate) {
673
                                putpacket("OK");        /* Ack before changing speed */
674
                                set_timer_3(baudrate); /* Set it */
675
                        }
676
#endif
677
                }
678
                break;
679
 
680
                }                       /* switch */
681
 
682
                /*
683
                 * reply to the request
684
                 */
685
 
686
                putpacket(output_buffer);
687
 
688
        } /* while */
689
}
690
 
691
/*
692
 * This function will generate a breakpoint exception.  It is used at the
693
 * beginning of a program to sync up with a debugger and can be used
694
 * otherwise as a quick means to stop program execution and "break" into
695
 * the debugger.
696
 */
697
void breakpoint(void)
698
{
699
        if (!initialized)
700
                return;
701
 
702
        __asm__ __volatile__("
703
                        .globl  breakinst
704
                        .set    noreorder
705
                        nop
706
breakinst:              break
707
                        nop
708
                        .set    reorder
709
        ");
710
}
711
 
712
void adel(void)
713
{
714
        __asm__ __volatile__("
715
                        .globl  adel
716
                        la      $8,0x80000001
717
                        lw      $9,0($8)
718
        ");
719
}
720
 
721
/*
722
 * Print registers (on target console)
723
 * Used only to debug the stub...
724
 */
725
void show_gdbregs(struct gdb_regs * regs)
726
{
727
        /*
728
         * Saved main processor registers
729
         */
730
        printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
731
               regs->reg0, regs->reg1, regs->reg2, regs->reg3,
732
               regs->reg4, regs->reg5, regs->reg6, regs->reg7);
733
        printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
734
               regs->reg8, regs->reg9, regs->reg10, regs->reg11,
735
               regs->reg12, regs->reg13, regs->reg14, regs->reg15);
736
        printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
737
               regs->reg16, regs->reg17, regs->reg18, regs->reg19,
738
               regs->reg20, regs->reg21, regs->reg22, regs->reg23);
739
        printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
740
               regs->reg24, regs->reg25, regs->reg26, regs->reg27,
741
               regs->reg28, regs->reg29, regs->reg30, regs->reg31);
742
 
743
        /*
744
         * Saved cp0 registers
745
         */
746
        printk("epc  : %08lx\nStatus: %08lx\nCause : %08lx\n",
747
               regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
748
}

powered by: WebSVN 2.1.0

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