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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [kernel/] [current/] [include/] [mboxt2.inl] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
#ifndef CYGONCE_KERNEL_MBOXT2_INL
2
#define CYGONCE_KERNEL_MBOXT2_INL
3
//==========================================================================
4
//
5
//      mboxt2.inl
6
//
7
//      Mboxt2 mbox template class implementation
8
//
9
//==========================================================================
10
// ####ECOSGPLCOPYRIGHTBEGIN####
11
// -------------------------------------------
12
// This file is part of eCos, the Embedded Configurable Operating System.
13
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2006 Free Software Foundation, Inc.
14
//
15
// eCos is free software; you can redistribute it and/or modify it under
16
// the terms of the GNU General Public License as published by the Free
17
// Software Foundation; either version 2 or (at your option) any later
18
// version.
19
//
20
// eCos is distributed in the hope that it will be useful, but WITHOUT
21
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23
// for more details.
24
//
25
// You should have received a copy of the GNU General Public License
26
// along with eCos; if not, write to the Free Software Foundation, Inc.,
27
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
28
//
29
// As a special exception, if other files instantiate templates or use
30
// macros or inline functions from this file, or you compile this file
31
// and link it with other works to produce a work based on this file,
32
// this file does not by itself cause the resulting work to be covered by
33
// the GNU General Public License. However the source code for this file
34
// must still be made available in accordance with section (3) of the GNU
35
// General Public License v2.
36
//
37
// This exception does not invalidate any other reasons why a work based
38
// on this file might be covered by the GNU General Public License.
39
// -------------------------------------------
40
// ####ECOSGPLCOPYRIGHTEND####
41
//==========================================================================
42
//#####DESCRIPTIONBEGIN####
43
//
44
// Author(s):   hmt
45
// Contributors:        hmt
46
// Date:        1998-02-10
47
// Purpose:     Mboxt2 template implementation
48
// Description: This file contains the implementations of the mboxt2
49
//              template classes.
50
//
51
//####DESCRIPTIONEND####
52
//
53
//==========================================================================
54
 
55
#include          // base kernel types
56
#include         // tracing macros
57
#include          // assertion macros
58
#include        // instrumentation
59
 
60
#include        // our header
61
 
62
#include        // thread inlines
63
#include         // scheduler inlines
64
#include         // clock inlines
65
 
66
// -------------------------------------------------------------------------
67
// inline function for awakening waiting threads
68
 
69
template 
70
inline void
71
Cyg_Mboxt2::wakeup_winner( const T &msg )
72
{
73
    CYG_ASSERT( !get_threadq.empty(), "Where did the winner go?" );
74
 
75
    // The queue is non-empty, so grab the next thread and wake it up.
76
    Cyg_Thread *thread = get_threadq.dequeue();
77
 
78
    CYG_ASSERTCLASS( thread, "Bad thread pointer");
79
 
80
    T *msg_ret = (T *)(thread->get_wait_info());
81
    *msg_ret = msg;
82
 
83
    thread->set_wake_reason( Cyg_Thread::DONE );
84
    thread->wake();
85
 
86
    CYG_INSTRUMENT_MBOXT(WAKE, this, thread);
87
}
88
 
89
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
90
template 
91
inline void
92
Cyg_Mboxt2::wakeup_putter( void )
93
{
94
    if( !put_threadq.empty() ) {
95
        // The queue is non-empty, so grab the next thread and wake it up.
96
        Cyg_Thread *thread = put_threadq.dequeue();
97
 
98
        CYG_ASSERTCLASS( thread, "Bad thread pointer");
99
 
100
        T *new_msg = (T *)(thread->get_wait_info());
101
 
102
        cyg_count32 in = base + (count++);
103
        if ( size <= in )
104
            in -= size;
105
 
106
        CYG_ASSERT( size > in, "in overflow" );
107
        CYG_ASSERT( 0 <= in, "in overflow" );
108
        CYG_ASSERT( size >= count, "count overflow" );
109
 
110
        itemqueue[ in ] = *new_msg;
111
 
112
        thread->set_wake_reason( Cyg_Thread::DONE );
113
        thread->wake();
114
 
115
        CYG_INSTRUMENT_MBOXT(WAKE, this, thread);
116
    }
117
}
118
#endif
119
 
120
// -------------------------------------------------------------------------
121
// Constructor
122
 
123
template 
124
Cyg_Mboxt2::Cyg_Mboxt2()
125
{
126
    CYG_REPORT_FUNCTION();
127
    base = 0;
128
    count = 0;
129
    CYG_REPORT_RETURN();
130
}
131
 
132
// -------------------------------------------------------------------------
133
// Destructor
134
 
135
template 
136
Cyg_Mboxt2::~Cyg_Mboxt2()
137
{
138
    CYG_REPORT_FUNCTION();
139
#if 0
140
    CYG_ASSERT( 0 == count, "Deleting mboxt2 with messages");
141
    CYG_ASSERT( get_threadq.empty(), "Deleting mboxt2 with threads waiting to get");
142
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
143
    CYG_ASSERT( put_threadq.empty(), "Deleting mboxt2 with threads waiting to put");
144
#endif
145
#endif
146
    // Prevent preemption
147
    Cyg_Scheduler::lock();
148
 
149
    while ( ! get_threadq.empty() ) {
150
        Cyg_Thread *thread = get_threadq.dequeue();
151
        thread->set_wake_reason( Cyg_Thread::DESTRUCT );
152
        thread->wake();
153
    }
154
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
155
    while ( ! put_threadq.empty() ) {
156
        Cyg_Thread *thread = put_threadq.dequeue();
157
        thread->set_wake_reason( Cyg_Thread::DESTRUCT );
158
        thread->wake();
159
    }
160
#endif
161
 
162
    // Unlock the scheduler and maybe switch threads
163
    Cyg_Scheduler::unlock();
164
    CYG_REPORT_RETURN();
165
}
166
 
167
// -------------------------------------------------------------------------
168
// debugging/assert function
169
 
170
#ifdef CYGDBG_USE_ASSERTS
171
 
172
template 
173
cyg_bool
174
Cyg_Mboxt2::check_this(cyg_assert_class_zeal zeal) const
175
{
176
    if ( Cyg_Thread::DESTRUCT == Cyg_Thread::self()->get_wake_reason() )
177
        // then the whole thing is invalid, and we know it.
178
        // so return OK, since this check should NOT make an error.
179
        return true;
180
 
181
    // check that we have a non-NULL pointer first
182
    if( this == NULL ) return false;
183
 
184
#if 0 // thread queues do not have checking funcs.
185
    if ( ! get_threadq.check_this( zeal ) ) return false;
186
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
187
    if ( ! put_threadq.check_this( zeal ) ) return false;
188
#endif
189
#endif
190
 
191
    switch( zeal )
192
    {
193
    case cyg_system_test:
194
    case cyg_extreme:
195
    case cyg_thorough:
196
    case cyg_quick:
197
    case cyg_trivial:
198
        // plenty of scope for fencepost problems here
199
        if ( size < count ) return false;
200
        if ( size <= base ) return false;
201
        if ( 0 > count ) return false;
202
        if ( 0 > base  ) return false;
203
 
204
        // Comments about needing 2 queues elided; they're not true in this
205
        // immediate-dispatch model.  I think we could get away with only
206
        // one queue now, biut is it worth it?  4 bytes of redundant info
207
        // buys a lot of correctness.
208
 
209
    case cyg_none:
210
    default:
211
        break;
212
    };
213
 
214
    return true;
215
}
216
 
217
#endif
218
 
219
 
220
// -------------------------------------------------------------------------
221
// From here downwards, these are the major functions of the template; if
222
// being genuinely used as a template they should probably not be inlined.
223
// If being used to construct a specific class, with explicit functions,
224
// then they should be.  This is controlled by:
225
 
226
#ifdef CYGIMP_MBOXT_INLINE
227
#define CYG_MBOXT_INLINE inline
228
#else
229
#define CYG_MBOXT_INLINE
230
#endif
231
 
232
// -------------------------------------------------------------------------
233
// Get an item, or wait for one to arrive
234
 
235
template 
236
CYG_MBOXT_INLINE cyg_bool
237
Cyg_Mboxt2::get( T &ritem )
238
{
239
    CYG_REPORT_FUNCTION();
240
    Cyg_Thread *self = Cyg_Thread::self();
241
 
242
    // Prevent preemption
243
    Cyg_Scheduler::lock();
244
 
245
    CYG_ASSERTCLASS( this, "Bad this pointer");
246
 
247
    CYG_INSTRUMENT_MBOXT(GET, this, count);
248
 
249
    if ( 0 < count ) {
250
        CYG_INSTRUMENT_MBOXT(GOT, this, count);
251
 
252
        ritem = itemqueue[ (count--, base++) ];
253
        CYG_ASSERT( 0 <= count, "Count went -ve" );
254
        CYG_ASSERT( size >= base, "Base overflow" );
255
 
256
        if ( size <= base )
257
            base = 0;
258
 
259
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
260
        wakeup_putter();
261
#endif
262
 
263
        CYG_ASSERTCLASS( this, "Bad this pointer");
264
 
265
        // Unlock the scheduler and definitely switch threads
266
        Cyg_Scheduler::unlock();
267
 
268
        CYG_REPORT_RETVAL( true );
269
        return true;
270
    }
271
 
272
    self->set_wait_info( (CYG_ADDRWORD)&ritem );
273
    self->set_sleep_reason( Cyg_Thread::WAIT );
274
    self->sleep();
275
    get_threadq.enqueue( self );
276
 
277
    CYG_INSTRUMENT_MBOXT(WAIT, this, count);
278
 
279
    CYG_ASSERTCLASS( this, "Bad this pointer");
280
 
281
    // Unlock scheduler and allow other threads to run
282
    Cyg_Scheduler::unlock_reschedule();
283
 
284
    cyg_bool result = true;
285
    switch( self->get_wake_reason() )
286
    {
287
    case Cyg_Thread::DESTRUCT:
288
    case Cyg_Thread::BREAK:
289
        result = false;
290
        break;
291
 
292
    case Cyg_Thread::EXIT:
293
        self->exit();
294
        break;
295
 
296
    default:
297
        break;
298
    }
299
 
300
    CYG_REPORT_RETVAL( result );
301
    return result;
302
}
303
 
304
 
305
// -------------------------------------------------------------------------
306
// Try to get an item with an absolute timeout and return success.
307
 
308
#ifdef CYGFUN_KERNEL_THREADS_TIMER
309
template 
310
CYG_MBOXT_INLINE cyg_bool
311
Cyg_Mboxt2::get( T &ritem, cyg_tick_count abs_timeout )
312
{
313
    CYG_REPORT_FUNCTION();
314
 
315
    Cyg_Thread *self = Cyg_Thread::self();
316
 
317
    // Prevent preemption
318
    Cyg_Scheduler::lock();
319
 
320
    CYG_ASSERTCLASS( this, "Bad this pointer");
321
 
322
    CYG_INSTRUMENT_MBOXT(GET, this, count);
323
 
324
    if ( 0 < count ) {
325
        CYG_INSTRUMENT_MBOXT(GOT, this, count);
326
 
327
        ritem = itemqueue[ (count--, base++) ];
328
        CYG_ASSERT( 0 <= count, "Count went -ve" );
329
        CYG_ASSERT( size >= base, "Base overflow" );
330
 
331
        if ( size <= base )
332
            base = 0;
333
 
334
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
335
        wakeup_putter();
336
#endif
337
 
338
        CYG_ASSERTCLASS( this, "Bad this pointer");
339
 
340
        // Unlock the scheduler and maybe switch threads
341
        Cyg_Scheduler::unlock();
342
 
343
        CYG_REPORT_RETVAL( true );
344
        return true;
345
    }
346
 
347
    // Set the timer
348
    self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT );
349
 
350
    // If the timeout is in the past, the wake reason will have been set to
351
    // something other than NONE already. If so, skip the wait and go
352
    // straight to unlock.
353
 
354
    if( Cyg_Thread::NONE == self->get_wake_reason() ) {
355
        self->set_wait_info( (CYG_ADDRWORD)&ritem );
356
        self->sleep();
357
        get_threadq.enqueue( self );
358
 
359
        CYG_INSTRUMENT_MBOXT(WAIT, this, count);
360
    }
361
 
362
    CYG_ASSERTCLASS( this, "Bad this pointer");
363
 
364
    // Unlock scheduler and allow other threads to run
365
    Cyg_Scheduler::unlock_reschedule();
366
 
367
    // clear the timer; if it actually fired, no worries.
368
    self->clear_timer();
369
 
370
    cyg_bool result = true;
371
    switch( self->get_wake_reason() )
372
    {
373
    case Cyg_Thread::TIMEOUT:
374
        result = false;
375
        CYG_INSTRUMENT_MBOXT(TIMEOUT, this, count);
376
        break;
377
 
378
    case Cyg_Thread::DESTRUCT:
379
    case Cyg_Thread::BREAK:
380
        result = false;
381
        break;
382
 
383
    case Cyg_Thread::EXIT:
384
        self->exit();
385
        break;
386
 
387
    default:
388
        break;
389
    }
390
 
391
    CYG_REPORT_RETVAL( result );
392
    return result;
393
}
394
#endif // CYGFUN_KERNEL_THREADS_TIMER
395
 
396
// -------------------------------------------------------------------------
397
// Try to get an item and return success.
398
 
399
template 
400
CYG_MBOXT_INLINE cyg_bool
401
Cyg_Mboxt2::tryget( T &ritem )
402
{
403
    CYG_REPORT_FUNCTION();
404
 
405
    // Prevent preemption
406
    Cyg_Scheduler::lock();
407
 
408
    CYG_ASSERTCLASS( this, "Bad this pointer");
409
 
410
    CYG_INSTRUMENT_MBOXT(TRY, this, count);
411
 
412
    cyg_bool result = ( 0 < count );
413
    // If the mboxt2 is not empty, grab an item and return it.
414
    if ( result ) {
415
        ritem = itemqueue[ (count--, base++) ];
416
        CYG_ASSERT( 0 <= count, "Count went -ve" );
417
        CYG_ASSERT( size >= base, "Base overflow" );
418
        if ( size <= base )
419
            base = 0;
420
 
421
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
422
        wakeup_putter();
423
#endif
424
    }
425
 
426
    // Unlock the scheduler and maybe switch threads
427
    Cyg_Scheduler::unlock();
428
    CYG_REPORT_RETVAL( result );
429
    return result;
430
}
431
 
432
// -------------------------------------------------------------------------
433
// get next item without removing it
434
template 
435
CYG_MBOXT_INLINE cyg_bool
436
Cyg_Mboxt2::peek_item( T &ritem )
437
{
438
    CYG_REPORT_FUNCTION();
439
 
440
    // Prevent preemption
441
    Cyg_Scheduler::lock();
442
 
443
    CYG_ASSERTCLASS( this, "Bad this pointer");
444
 
445
    CYG_INSTRUMENT_MBOXT(TRY, this, count);
446
 
447
    cyg_bool result = ( 0 < count );
448
    // If the mboxt2 is not empty, grab an item and return it.
449
    if ( result )
450
        ritem = itemqueue[ base ];
451
 
452
    // Unlock the scheduler and maybe switch threads
453
    Cyg_Scheduler::unlock();
454
    CYG_REPORT_RETVAL( result );
455
    return result;
456
}
457
 
458
// -------------------------------------------------------------------------
459
// Put an item in the queue; wait if full.
460
 
461
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
462
template 
463
CYG_MBOXT_INLINE cyg_bool
464
Cyg_Mboxt2::put( const T item )
465
{
466
    CYG_REPORT_FUNCTION();
467
 
468
    Cyg_Thread *self = Cyg_Thread::self();
469
 
470
    // Prevent preemption
471
    Cyg_Scheduler::lock();
472
 
473
    CYG_INSTRUMENT_MBOXT(PUT, this, count);
474
    CYG_ASSERTCLASS( this, "Bad this pointer");
475
 
476
    if ( size == count ) {
477
        CYG_ASSERT( get_threadq.empty(), "Threads waiting AND queue full?" );
478
 
479
        self->set_wait_info( (CYG_ADDRWORD)&item );
480
        self->set_sleep_reason( Cyg_Thread::WAIT );
481
        self->sleep();
482
        put_threadq.enqueue( self );
483
 
484
        CYG_INSTRUMENT_MBOXT(WAIT, this, count);
485
 
486
        CYG_ASSERTCLASS( this, "Bad this pointer");
487
 
488
        // when this returns, our item is in the queue.
489
        Cyg_Scheduler::unlock_reschedule();        // unlock, switch threads
490
 
491
        cyg_bool result = true;
492
        switch( self->get_wake_reason() )
493
        {
494
        case Cyg_Thread::DESTRUCT:
495
        case Cyg_Thread::BREAK:
496
            result = false;
497
            break;
498
 
499
        case Cyg_Thread::EXIT:
500
            self->exit();
501
            break;
502
 
503
        default:
504
            break;
505
        }
506
        CYG_REPORT_RETVAL( result );
507
        return result;
508
    }
509
 
510
    if ( !get_threadq.empty() ) {
511
        wakeup_winner( item );
512
        CYG_ASSERTCLASS( this, "Bad this pointer");
513
        Cyg_Scheduler::unlock();        // unlock, maybe switch threads
514
        CYG_REPORT_RETVAL( true );
515
        return true;
516
    }
517
 
518
    cyg_count32 in = base + (count++);
519
    if ( size <= in )
520
        in -= size;
521
 
522
    CYG_ASSERT( size > in, "in overflow" );
523
    CYG_ASSERT( 0 <= in, "in overflow" );
524
    CYG_ASSERT( size >= count, "count overflow" );
525
 
526
    itemqueue[ in ] = item;
527
 
528
    CYG_ASSERTCLASS( this, "Bad this pointer");
529
 
530
    // Unlock the scheduler and maybe switch threads
531
    Cyg_Scheduler::unlock();
532
    CYG_REPORT_RETVAL( true );
533
    return true;
534
}
535
 
536
// -------------------------------------------------------------------------
537
// Put an item in the queue; wait if full, with an absolute timeout;
538
// return success.
539
 
540
#ifdef CYGFUN_KERNEL_THREADS_TIMER
541
template 
542
CYG_MBOXT_INLINE cyg_bool
543
Cyg_Mboxt2::put( const T item, cyg_tick_count abs_timeout )
544
{
545
    CYG_REPORT_FUNCTION();
546
 
547
    Cyg_Thread *self = Cyg_Thread::self();
548
 
549
    // Prevent preemption
550
    Cyg_Scheduler::lock();
551
 
552
    CYG_INSTRUMENT_MBOXT(PUT, this, count);
553
    CYG_ASSERTCLASS( this, "Bad this pointer");
554
 
555
    if ( size == count ) {
556
 
557
        CYG_ASSERT( get_threadq.empty(), "Threads waiting AND queue full?" );
558
 
559
        // Set the timer
560
        self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT );
561
 
562
        // If the timeout is in the past, the wake reason will have been set to
563
        // something other than NONE already. If so, skip the wait and go
564
        // straight to unlock.
565
 
566
        if( Cyg_Thread::NONE == self->get_wake_reason() ) {
567
            self->set_wait_info( (CYG_ADDRWORD)&item );
568
            self->sleep();
569
            put_threadq.enqueue( self );
570
 
571
            CYG_INSTRUMENT_MBOXT(WAIT, this, count);
572
        }
573
 
574
        CYG_ASSERTCLASS( this, "Bad this pointer");
575
 
576
        // when this returns, our item is in the queue.
577
        Cyg_Scheduler::unlock_reschedule();        // unlock, switch threads
578
 
579
        // clear the timer; if it actually fired, no worries.
580
        self->clear_timer();
581
 
582
        cyg_bool result = true;
583
        switch( self->get_wake_reason() )
584
        {
585
        case Cyg_Thread::TIMEOUT:
586
            result = false;
587
            CYG_INSTRUMENT_MBOXT(TIMEOUT, this, count);
588
            break;
589
 
590
        case Cyg_Thread::DESTRUCT:
591
        case Cyg_Thread::BREAK:
592
            result = false;
593
            break;
594
 
595
        case Cyg_Thread::EXIT:
596
            self->exit();
597
            break;
598
 
599
        default:
600
            break;
601
        }
602
 
603
        CYG_REPORT_RETVAL( result );
604
        return result;
605
    }
606
 
607
 
608
    if ( !get_threadq.empty() ) {
609
        wakeup_winner( item );
610
        CYG_ASSERTCLASS( this, "Bad this pointer");
611
        Cyg_Scheduler::unlock();        // unlock, maybe switch threads
612
        CYG_REPORT_RETVAL( true );
613
        return true;
614
    }
615
 
616
    cyg_count32 in = base + (count++);
617
    if ( size <= in )
618
        in -= size;
619
 
620
    CYG_ASSERT( size > in, "in overflow" );
621
    CYG_ASSERT( 0 <= in, "in overflow" );
622
    CYG_ASSERT( size >= count, "count overflow" );
623
 
624
    itemqueue[ in ] = item;
625
 
626
    CYG_ASSERTCLASS( this, "Bad this pointer");
627
 
628
    // Unlock the scheduler and maybe switch threads
629
    Cyg_Scheduler::unlock();
630
    CYG_REPORT_RETVAL( true );
631
    return true;
632
}
633
#endif // CYGFUN_KERNEL_THREADS_TIMER
634
#endif // CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
635
 
636
// -------------------------------------------------------------------------
637
// Try to put an item in the queue and return success; queue may be full.
638
 
639
template 
640
CYG_MBOXT_INLINE cyg_bool
641
Cyg_Mboxt2::tryput( const T item )
642
{
643
    CYG_REPORT_FUNCTION();
644
 
645
    // Prevent preemption
646
    Cyg_Scheduler::lock();
647
 
648
    CYG_INSTRUMENT_MBOXT(PUT, this, count);
649
    CYG_ASSERTCLASS( this, "Bad this pointer");
650
 
651
    if ( size == count ) {
652
        CYG_ASSERT( get_threadq.empty(), "Threads waiting AND queue full?" );
653
        Cyg_Scheduler::unlock();        // unlock, maybe switch threads
654
        CYG_REPORT_RETVAL( false );
655
        return false;                   // the mboxt2 is full
656
    }
657
 
658
    if ( !get_threadq.empty() ) {
659
        CYG_ASSERT( 0 == count, "Threads waiting AND queue not empty" );
660
        wakeup_winner( item );
661
        Cyg_Scheduler::unlock();        // unlock, maybe switch threads
662
        CYG_REPORT_RETVAL( true );
663
        return true;
664
    }
665
 
666
    cyg_count32 in = base + (count++);
667
    if ( size <= in )
668
        in -= size;
669
 
670
    CYG_ASSERT( size > in, "in overflow" );
671
    CYG_ASSERT( 0 <= in, "in overflow" );
672
    CYG_ASSERT( size >= count, "count overflow" );
673
 
674
    itemqueue[ in ] = item;
675
 
676
    CYG_ASSERTCLASS( this, "Bad this pointer");
677
 
678
    // Unlock the scheduler and maybe switch threads
679
    Cyg_Scheduler::unlock();
680
 
681
    CYG_REPORT_RETVAL( true );
682
    return true;
683
}
684
 
685
 
686
// -------------------------------------------------------------------------
687
#endif // ifndef CYGONCE_KERNEL_MBOXT2_INL
688
// EOF mboxt2.inl

powered by: WebSVN 2.1.0

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