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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [SuperH_SH7216_Renesas/] [RTOSDemo/] [webserver/] [EMAC.c] - Blame information for rev 585

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 585 jeremybenn
/*
2
    FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
3
 
4
    ***************************************************************************
5
    *                                                                         *
6
    * If you are:                                                             *
7
    *                                                                         *
8
    *    + New to FreeRTOS,                                                   *
9
    *    + Wanting to learn FreeRTOS or multitasking in general quickly       *
10
    *    + Looking for basic training,                                        *
11
    *    + Wanting to improve your FreeRTOS skills and productivity           *
12
    *                                                                         *
13
    * then take a look at the FreeRTOS books - available as PDF or paperback  *
14
    *                                                                         *
15
    *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *
16
    *                  http://www.FreeRTOS.org/Documentation                  *
17
    *                                                                         *
18
    * A pdf reference manual is also available.  Both are usually delivered   *
19
    * to your inbox within 20 minutes to two hours when purchased between 8am *
20
    * and 8pm GMT (although please allow up to 24 hours in case of            *
21
    * exceptional circumstances).  Thank you for your support!                *
22
    *                                                                         *
23
    ***************************************************************************
24
 
25
    This file is part of the FreeRTOS distribution.
26
 
27
    FreeRTOS is free software; you can redistribute it and/or modify it under
28
    the terms of the GNU General Public License (version 2) as published by the
29
    Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
30
    ***NOTE*** The exception to the GPL is included to allow you to distribute
31
    a combined work that includes FreeRTOS without being obliged to provide the
32
    source code for proprietary components outside of the FreeRTOS kernel.
33
    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
34
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
35
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
36
    more details. You should have received a copy of the GNU General Public
37
    License and the FreeRTOS license exception along with FreeRTOS; if not it
38
    can be viewed here: http://www.freertos.org/a00114.html and also obtained
39
    by writing to Richard Barry, contact details for whom are available on the
40
    FreeRTOS WEB site.
41
 
42
    1 tab == 4 spaces!
43
 
44
    http://www.FreeRTOS.org - Documentation, latest information, license and
45
    contact details.
46
 
47
    http://www.SafeRTOS.com - A version that is certified for use in safety
48
    critical systems.
49
 
50
    http://www.OpenRTOS.com - Commercial support, development, porting,
51
    licensing and training services.
52
*/
53
 
54
/* Hardware specific includes. */
55
#include "iodefine.h"
56
#include "typedefine.h"
57
#include "hwEthernet.h"
58
#include "hwEthernetPhy.h"
59
 
60
/* FreeRTOS includes. */
61
#include "FreeRTOS.h"
62
#include "task.h"
63
#include "semphr.h"
64
 
65
/* uIP includes. */
66
#include "net/uip.h"
67
 
68
/* The time to wait between attempts to obtain a free buffer. */
69
#define emacBUFFER_WAIT_DELAY_ms                ( 3 / portTICK_RATE_MS )
70
 
71
/* The number of times emacBUFFER_WAIT_DELAY_ms should be waited before giving
72
up on attempting to obtain a free buffer all together. */
73
#define emacBUFFER_WAIT_ATTEMPTS        ( 30 )
74
 
75
/* The number of Rx descriptors. */
76
#define emacNUM_RX_DESCRIPTORS  3
77
 
78
/* The number of Tx descriptors.  When using uIP there is not point in having
79
more than two. */
80
#define emacNUM_TX_BUFFERS      2
81
 
82
/* The total number of EMAC buffers to allocate. */
83
#define emacNUM_BUFFERS         ( emacNUM_RX_DESCRIPTORS + emacNUM_TX_BUFFERS )
84
 
85
/* The time to wait for the Tx descriptor to become free. */
86
#define emacTX_WAIT_DELAY_ms ( 10 / portTICK_RATE_MS )
87
 
88
/* The total number of times to wait emacTX_WAIT_DELAY_ms for the Tx descriptor to
89
become free. */
90
#define emacTX_WAIT_ATTEMPTS ( 5 )
91
 
92
/* Only Rx end and Tx end interrupts are used by this driver. */
93
#define emacTX_END_INTERRUPT    ( 1UL << 21UL )
94
#define emacRX_END_INTERRUPT    ( 1UL << 18UL )
95
 
96
/*-----------------------------------------------------------*/
97
 
98
/* The buffers and descriptors themselves. */
99
#pragma section RX_DESCR
100
        ethfifo xRxDescriptors[ emacNUM_RX_DESCRIPTORS ];
101
#pragma section TX_DESCR
102
        ethfifo xTxDescriptors[ emacNUM_TX_BUFFERS ];
103
#pragma section _ETHERNET_BUFFERS
104
        char xEthernetBuffers[ emacNUM_BUFFERS ][ UIP_BUFSIZE ];
105
#pragma section
106
 
107
/* Used to indicate which buffers are free and which are in use.  If an index
108
contains 0 then the corresponding buffer in xEthernetBuffers is free, otherwise
109
the buffer is in use or about to be used. */
110
static unsigned char ucBufferInUse[ emacNUM_BUFFERS ];
111
 
112
/*-----------------------------------------------------------*/
113
 
114
/*
115
 * Initialise both the Rx and Tx descriptors.
116
 */
117
static void prvInitialiseDescriptors( void );
118
 
119
/*
120
 * Return a pointer to a free buffer within xEthernetBuffers.
121
 */
122
static unsigned char *prvGetNextBuffer( void );
123
 
124
/*
125
 * Return a buffer to the list of free buffers.
126
 */
127
static void prvReturnBuffer( unsigned char *pucBuffer );
128
 
129
/*
130
 * Examine the status of the next Rx FIFO to see if it contains new data.
131
 */
132
static unsigned long prvCheckRxFifoStatus( void );
133
 
134
/*
135
 * Setup the microcontroller for communication with the PHY.
136
 */
137
static void prvSetupPortPinsAndReset( void );
138
 
139
/*
140
 * Configure the Ethernet interface peripherals.
141
 */
142
static void prvConfigureEtherCAndEDMAC( void );
143
 
144
/*
145
 * Something has gone wrong with the descriptor usage.  Reset all the buffers
146
 * and descriptors.
147
 */
148
static void prvResetEverything( void );
149
 
150
/*-----------------------------------------------------------*/
151
 
152
/* Points to the Rx descriptor currently in use. */
153
static ethfifo *xCurrentRxDesc = NULL;
154
 
155
/* The buffer used by the uIP stack to both receive and send.  This points to
156
one of the Ethernet buffers when its actually in use. */
157
unsigned char *uip_buf = NULL;
158
 
159
/*-----------------------------------------------------------*/
160
 
161
void vInitEmac( void )
162
{
163
        /* Setup the SH hardware for MII communications. */
164
        prvSetupPortPinsAndReset();
165
 
166
        /* Set the Rx and Tx descriptors into their initial state. */
167
        prvInitialiseDescriptors();
168
 
169
        /* Set the MAC address into the ETHERC */
170
        EtherC.MAHR =   ( ( unsigned long ) configMAC_ADDR0 << 24UL ) |
171
                                        ( ( unsigned long ) configMAC_ADDR1 << 16UL ) |
172
                                        ( ( unsigned long ) configMAC_ADDR2 << 8UL ) |
173
                                        ( unsigned long ) configMAC_ADDR3;
174
 
175
        EtherC.MALR.BIT.MA = ( ( unsigned long ) configMAC_ADDR4 << 8UL ) |
176
                                                 ( unsigned long ) configMAC_ADDR5;
177
 
178
        /* Perform rest of interface hardware configuration. */
179
        prvConfigureEtherCAndEDMAC();
180
 
181
        /* Nothing received yet, so uip_buf points nowhere. */
182
        uip_buf = NULL;
183
 
184
        /* Initialize the PHY */
185
        phyReset();
186
}
187
/*-----------------------------------------------------------*/
188
 
189
void vEMACWrite( void )
190
{
191
long x;
192
 
193
        /* Wait until the second transmission of the last packet has completed. */
194
        for( x = 0; x < emacTX_WAIT_ATTEMPTS; x++ )
195
        {
196
                if( ( xTxDescriptors[ 1 ].status & ACT ) != 0 )
197
                {
198
                        /* Descriptor is still active. */
199
                        vTaskDelay( emacTX_WAIT_DELAY_ms );
200
                }
201
                else
202
                {
203
                        break;
204
                }
205
        }
206
 
207
        /* Is the descriptor free after waiting for it? */
208
        if( ( xTxDescriptors[ 1 ].status & ACT ) != 0 )
209
        {
210
                /* Something has gone wrong. */
211
                prvResetEverything();
212
        }
213
 
214
        /* Setup both descriptors to transmit the frame. */
215
        xTxDescriptors[ 0 ].buf_p = ( char * ) uip_buf;
216
        xTxDescriptors[ 0 ].bufsize = uip_len;
217
        xTxDescriptors[ 1 ].buf_p = ( char * ) uip_buf;
218
        xTxDescriptors[ 1 ].bufsize = uip_len;
219
 
220
        /* uip_buf is being sent by the Tx descriptor.  Allocate a new buffer
221
        for use by the stack. */
222
        uip_buf = prvGetNextBuffer();
223
 
224
        /* Clear previous settings and go. */
225
        xTxDescriptors[0].status &= ~( FP1 | FP0 );
226
        xTxDescriptors[0].status |= ( FP1 | FP0 | ACT );
227
        xTxDescriptors[1].status &= ~( FP1 | FP0 );
228
        xTxDescriptors[1].status |= ( FP1 | FP0 | ACT );
229
 
230
        EDMAC.EDTRR.LONG = 0x00000001;
231
}
232
/*-----------------------------------------------------------*/
233
 
234
unsigned long ulEMACRead( void )
235
{
236
unsigned long ulBytesReceived;
237
 
238
        ulBytesReceived = prvCheckRxFifoStatus();
239
 
240
        if( ulBytesReceived > 0 )
241
        {
242
                xCurrentRxDesc->status &= ~( FP1 | FP0 );
243
                xCurrentRxDesc->status |= ACT;
244
 
245
                if( EDMAC.EDRRR.LONG == 0x00000000L )
246
                {
247
                        /* Restart Ethernet if it has stopped */
248
                        EDMAC.EDRRR.LONG = 0x00000001L;
249
                }
250
 
251
                /* Mark the pxDescriptor buffer as free as uip_buf is going to be set to
252
                the buffer that contains the received data. */
253
                prvReturnBuffer( uip_buf );
254
 
255
                uip_buf = ( void * ) xCurrentRxDesc->buf_p;
256
 
257
                /* Move onto the next buffer in the ring. */
258
                xCurrentRxDesc = xCurrentRxDesc->next;
259
        }
260
 
261
        return ulBytesReceived;
262
}
263
/*-----------------------------------------------------------*/
264
 
265
long lEMACWaitForLink( void )
266
{
267
long lReturn;
268
 
269
        /* Set the link status. */
270
        switch( phyStatus() )
271
        {
272
                /* Half duplex link */
273
                case PHY_LINK_100H:
274
                case PHY_LINK_10H:
275
                                                                EtherC.ECMR.BIT.DM = 0;
276
                                                                lReturn = pdPASS;
277
                                                                break;
278
 
279
                /* Full duplex link */
280
                case PHY_LINK_100F:
281
                case PHY_LINK_10F:
282
                                                                EtherC.ECMR.BIT.DM = 1;
283
                                                                lReturn = pdPASS;
284
                                                                break;
285
 
286
                default:
287
                                                                lReturn = pdFAIL;
288
                                                                break;
289
        }
290
 
291
        if( lReturn == pdPASS )
292
        {
293
                /* Enable receive and transmit. */
294
                EtherC.ECMR.BIT.RE = 1;
295
                EtherC.ECMR.BIT.TE = 1;
296
 
297
                /* Enable EDMAC receive */
298
                EDMAC.EDRRR.LONG = 0x1;
299
        }
300
 
301
        return lReturn;
302
}
303
/*-----------------------------------------------------------*/
304
 
305
static void prvInitialiseDescriptors( void )
306
{
307
ethfifo *pxDescriptor;
308
long x;
309
 
310
        for( x = 0; x < emacNUM_BUFFERS; x++ )
311
        {
312
                /* Ensure none of the buffers are shown as in use at the start. */
313
                ucBufferInUse[ x ] = pdFALSE;
314
        }
315
 
316
        /* Initialise the Rx descriptors. */
317
        for( x = 0; x < emacNUM_RX_DESCRIPTORS; x++ )
318
        {
319
                pxDescriptor = &( xRxDescriptors[ x ] );
320
                pxDescriptor->buf_p = &( xEthernetBuffers[ x ][ 0 ] );
321
 
322
                pxDescriptor->bufsize = UIP_BUFSIZE;
323
                pxDescriptor->size = 0;
324
                pxDescriptor->status = ACT;
325
                pxDescriptor->next = &xRxDescriptors[ x + 1 ];
326
 
327
                /* Mark this buffer as in use. */
328
                ucBufferInUse[ x ] = pdTRUE;
329
        }
330
 
331
        /* The last descriptor points back to the start. */
332
        pxDescriptor->status |= DL;
333
        pxDescriptor->next = &xRxDescriptors[ 0 ];
334
 
335
        /* Initialise the Tx descriptors. */
336
        for( x = 0; x < emacNUM_TX_BUFFERS; x++ )
337
        {
338
                pxDescriptor = &( xTxDescriptors[ x ] );
339
 
340
                /* A buffer is not allocated to the Tx descriptor until a send is
341
                actually required. */
342
                pxDescriptor->buf_p = NULL;
343
 
344
                pxDescriptor->bufsize = UIP_BUFSIZE;
345
                pxDescriptor->size = 0;
346
                pxDescriptor->status = 0;
347
                pxDescriptor->next = &xTxDescriptors[ x + 1 ];
348
        }
349
 
350
        /* The last descriptor points back to the start. */
351
        pxDescriptor->status |= DL;
352
        pxDescriptor->next = &( xTxDescriptors[ 0 ] );
353
 
354
        /* Use the first Rx descriptor to start with. */
355
        xCurrentRxDesc = &( xRxDescriptors[ 0 ] );
356
}
357
/*-----------------------------------------------------------*/
358
 
359
static unsigned char *prvGetNextBuffer( void )
360
{
361
long x;
362
unsigned char *pucReturn = NULL;
363
unsigned long ulAttempts = 0;
364
 
365
        while( pucReturn == NULL )
366
        {
367
                /* Look through the buffers to find one that is not in use by
368
                anything else. */
369
                for( x = 0; x < emacNUM_BUFFERS; x++ )
370
                {
371
                        if( ucBufferInUse[ x ] == pdFALSE )
372
                        {
373
                                ucBufferInUse[ x ] = pdTRUE;
374
                                pucReturn = ( unsigned char * ) &( xEthernetBuffers[ x ][ 0 ] );
375
                                break;
376
                        }
377
                }
378
 
379
                /* Was a buffer found? */
380
                if( pucReturn == NULL )
381
                {
382
                        ulAttempts++;
383
 
384
                        if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )
385
                        {
386
                                break;
387
                        }
388
 
389
                        /* Wait then look again. */
390
                        vTaskDelay( emacBUFFER_WAIT_DELAY_ms );
391
                }
392
        }
393
 
394
        return pucReturn;
395
}
396
/*-----------------------------------------------------------*/
397
 
398
static void prvReturnBuffer( unsigned char *pucBuffer )
399
{
400
unsigned long ul;
401
 
402
        /* Return a buffer to the pool of free buffers. */
403
        for( ul = 0; ul < emacNUM_BUFFERS; ul++ )
404
        {
405
                if( &( xEthernetBuffers[ ul ][ 0 ] ) == ( void * ) pucBuffer )
406
                {
407
                        ucBufferInUse[ ul ] = pdFALSE;
408
                        break;
409
                }
410
        }
411
}
412
/*-----------------------------------------------------------*/
413
 
414
static void prvResetEverything( void )
415
{
416
        /* Temporary code just to see if this gets called.  This function has not
417
        been implemented. */
418
        portDISABLE_INTERRUPTS();
419
        for( ;; );
420
}
421
/*-----------------------------------------------------------*/
422
 
423
static unsigned long prvCheckRxFifoStatus( void )
424
{
425
unsigned long ulReturn = 0;
426
 
427
        if( ( xCurrentRxDesc->status & ACT ) != 0 )
428
        {
429
                /* Current descriptor is still active. */
430
        }
431
        else if( ( xCurrentRxDesc->status & FE ) != 0 )
432
        {
433
                /* Frame error.  Clear the error. */
434
                xCurrentRxDesc->status &= ~( FP1 | FP0 | FE );
435
                xCurrentRxDesc->status &= ~( RMAF | RRF | RTLF | RTSF | PRE | CERF );
436
                xCurrentRxDesc->status |= ACT;
437
                xCurrentRxDesc = xCurrentRxDesc->next;
438
 
439
                if( EDMAC.EDRRR.LONG == 0x00000000UL )
440
                {
441
                        /* Restart Ethernet if it has stopped. */
442
                        EDMAC.EDRRR.LONG = 0x00000001UL;
443
                }
444
        }
445
        else
446
        {
447
                /* The descriptor contains a frame.  Because of the size of the buffers
448
                the frame should always be complete. */
449
                if( (xCurrentRxDesc->status & FP0) == FP0 )
450
                {
451
                        ulReturn = xCurrentRxDesc->size;
452
                }
453
                else
454
                {
455
                        /* Do not expect to get here. */
456
                        prvResetEverything();
457
                }
458
        }
459
 
460
        return ulReturn;
461
}
462
/*-----------------------------------------------------------*/
463
 
464
static void prvSetupPortPinsAndReset( void )
465
{
466
        /* Initialisation code taken from Renesas example project. */
467
 
468
        PFC.PACRL4.BIT.PA12MD = 0x7;            /* Set TX_CLK input      (EtherC) */
469
        PFC.PACRL3.BIT.PA11MD = 0x7;            /* Set TX_EN output      (EtherC) */
470
        PFC.PACRL3.BIT.PA10MD = 0x7;            /* Set MII_TXD0 output   (EtherC) */
471
        PFC.PACRL3.BIT.PA9MD  = 0x7;            /* Set MII_TXD1 output   (EtherC) */
472
        PFC.PACRL3.BIT.PA8MD  = 0x7;            /* Set MII_TXD2 output   (EtherC) */
473
        PFC.PACRL2.BIT.PA7MD  = 0x7;            /* Set MII_TXD3 output   (EtherC) */
474
        PFC.PACRL2.BIT.PA6MD  = 0x7;            /* Set TX_ER output      (EtherC) */
475
        PFC.PDCRH4.BIT.PD31MD = 0x7;            /* Set RX_DV input       (EtherC) */
476
        PFC.PDCRH4.BIT.PD30MD = 0x7;            /* Set RX_ER input       (EtherC) */
477
        PFC.PDCRH4.BIT.PD29MD = 0x7;            /* Set MII_RXD3 input    (EtherC) */
478
        PFC.PDCRH4.BIT.PD28MD = 0x7;            /* Set MII_RXD2 input    (EtherC) */
479
        PFC.PDCRH3.BIT.PD27MD = 0x7;            /* Set MII_RXD1 input    (EtherC) */
480
        PFC.PDCRH3.BIT.PD26MD = 0x7;            /* Set MII_RXD0 input    (EtherC) */
481
        PFC.PDCRH3.BIT.PD25MD = 0x7;            /* Set RX_CLK input      (EtherC) */
482
        PFC.PDCRH3.BIT.PD24MD = 0x7;            /* Set CRS input         (EtherC) */
483
        PFC.PDCRH2.BIT.PD23MD = 0x7;            /* Set COL input         (EtherC) */
484
        PFC.PDCRH2.BIT.PD22MD = 0x7;            /* Set WOL output        (EtherC) */
485
        PFC.PDCRH2.BIT.PD21MD = 0x7;            /* Set EXOUT output      (EtherC) */
486
        PFC.PDCRH2.BIT.PD20MD = 0x7;            /* Set MDC output        (EtherC) */
487
        PFC.PDCRH1.BIT.PD19MD = 0x7;            /* Set LINKSTA input     (EtherC) */
488
        PFC.PDCRH1.BIT.PD18MD = 0x7;            /* Set MDIO input/output (EtherC) */
489
 
490
        STB.CR4.BIT._ETHER = 0x0;
491
        EDMAC.EDMR.BIT.SWR = 1;
492
 
493
        /* Crude wait for reset to complete. */
494
        vTaskDelay( 500 / portTICK_RATE_MS );
495
}
496
/*-----------------------------------------------------------*/
497
 
498
static void prvConfigureEtherCAndEDMAC( void )
499
{
500
        /* Initialisation code taken from Renesas example project. */
501
 
502
        /* TODO:    Check   bit 5   */
503
        EtherC.ECSR.LONG = 0x00000037;                          /* Clear all EtherC statuS BFR, PSRTO, LCHNG, MPD, ICD */
504
 
505
        /* TODO:    Check   bit 5   */
506
        EtherC.ECSIPR.LONG = 0x00000020;                        /* Disable EtherC status change interrupt */
507
        EtherC.RFLR.LONG = 1518;                                        /* Ether payload is 1500+ CRC */
508
        EtherC.IPGR.LONG = 0x00000014;                          /* Intergap is 96-bit time */
509
 
510
        /* EDMAC */
511
        EDMAC.EESR.LONG = 0x47FF0F9F;                           /* Clear all EtherC and EDMAC status bits */
512
        EDMAC.RDLAR = ( void * ) xCurrentRxDesc;        /* Initialaize Rx Descriptor List Address */
513
        EDMAC.TDLAR = &( xTxDescriptors[ 0 ] );          /* Initialaize Tx Descriptor List Address */
514
        EDMAC.TRSCER.LONG = 0x00000000;                         /* Copy-back status is RFE & TFE only   */
515
        EDMAC.TFTR.LONG = 0x00000000;                           /* Threshold of Tx_FIFO */
516
        EDMAC.FDR.LONG = 0x00000000;                            /* Transmit fifo & receive fifo is 256 bytes */
517
        EDMAC.RMCR.LONG = 0x00000003;                           /* Receive function is normal mode(continued) */
518
 
519
        /* Set the EDMAC interrupt priority - the interrupt priority must be
520
        configKERNEL_INTERRUPT_PRIORITY no matter which peripheral is used to
521
        generate the tick interrupt. */
522
        INTC.IPR19.BIT._EDMAC = portKERNEL_INTERRUPT_PRIORITY;
523
        EDMAC.EESIPR.LONG = emacTX_END_INTERRUPT | emacRX_END_INTERRUPT;        /* Enable Rx and Tx end interrupts. */
524
 
525
        /* Clear the interrupt flag. */
526
        CMT0.CMCSR.BIT.CMF = 0;
527
}
528
/*-----------------------------------------------------------*/
529
 
530
void vEMAC_ISR_Handler( void )
531
{
532
unsigned long ul = EDMAC.EESR.LONG;
533
long lHigherPriorityTaskWoken = pdFALSE;
534
extern xSemaphoreHandle xEMACSemaphore;
535
static long ulTxEndInts = 0;
536
 
537
        /* Has a Tx end occurred? */
538
        if( ul & emacTX_END_INTERRUPT )
539
        {
540
                ++ulTxEndInts;
541
                if( ulTxEndInts >= 2 )
542
                {
543
                        /* Only return the buffer to the pool once both Txes have completed. */
544
                        prvReturnBuffer( ( void * ) xTxDescriptors[ 0 ].buf_p );
545
                        ulTxEndInts = 0;
546
                }
547
                EDMAC.EESR.LONG = emacTX_END_INTERRUPT;
548
        }
549
 
550
        /* Has an Rx end occurred? */
551
        if( ul & emacRX_END_INTERRUPT )
552
        {
553
                /* Make sure the Ethernet task is not blocked waiting for a packet. */
554
                xSemaphoreGiveFromISR( xEMACSemaphore, &lHigherPriorityTaskWoken );
555
                portYIELD_FROM_ISR( lHigherPriorityTaskWoken );
556
                EDMAC.EESR.LONG = emacRX_END_INTERRUPT;
557
        }
558
}

powered by: WebSVN 2.1.0

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