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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [doc/] [html/] [user-guide/] [clocks-and-alarm-handlers.html] - Diff between revs 28 and 174

Only display areas with differences | Details | Blame | View Log

Rev 28 Rev 174
<!-- Copyright (C) 2003 Red Hat, Inc.                                -->
<!-- Copyright (C) 2003 Red Hat, Inc.                                -->
<!-- This material may be distributed only subject to the terms      -->
<!-- This material may be distributed only subject to the terms      -->
<!-- and conditions set forth in the Open Publication License, v1.0  -->
<!-- and conditions set forth in the Open Publication License, v1.0  -->
<!-- or later (the latest version is presently available at          -->
<!-- or later (the latest version is presently available at          -->
<!-- http://www.opencontent.org/openpub/).                           -->
<!-- http://www.opencontent.org/openpub/).                           -->
<!-- Distribution of the work or derivative of the work in any       -->
<!-- Distribution of the work or derivative of the work in any       -->
<!-- standard (paper) book form is prohibited unless prior           -->
<!-- standard (paper) book form is prohibited unless prior           -->
<!-- permission is obtained from the copyright holder.               -->
<!-- permission is obtained from the copyright holder.               -->
<HTML
<HTML
><HEAD
><HEAD
><TITLE
><TITLE
>More Features &#8212; Clocks and Alarm
>More Features &#8212; Clocks and Alarm
Handlers</TITLE
Handlers</TITLE
><meta name="MSSmartTagsPreventParsing" content="TRUE">
><meta name="MSSmartTagsPreventParsing" content="TRUE">
<META
<META
NAME="GENERATOR"
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
"><LINK
"><LINK
REL="HOME"
REL="HOME"
TITLE="eCos User Guide"
TITLE="eCos User Guide"
HREF="ecos-user-guide.html"><LINK
HREF="ecos-user-guide.html"><LINK
REL="UP"
REL="UP"
TITLE="Programming With eCos"
TITLE="Programming With eCos"
HREF="user-guide-programming.html"><LINK
HREF="user-guide-programming.html"><LINK
REL="PREVIOUS"
REL="PREVIOUS"
TITLE="A Sample Program with Two Threads"
TITLE="A Sample Program with Two Threads"
HREF="sample-twothreads.html"><LINK
HREF="sample-twothreads.html"><LINK
REL="NEXT"
REL="NEXT"
TITLE="The eCos Configuration Tool"
TITLE="The eCos Configuration Tool"
HREF="the-ecos-configuration-tool.html"></HEAD
HREF="the-ecos-configuration-tool.html"></HEAD
><BODY
><BODY
CLASS="CHAPTER"
CLASS="CHAPTER"
BGCOLOR="#FFFFFF"
BGCOLOR="#FFFFFF"
TEXT="#000000"
TEXT="#000000"
LINK="#0000FF"
LINK="#0000FF"
VLINK="#840084"
VLINK="#840084"
ALINK="#0000FF"
ALINK="#0000FF"
><DIV
><DIV
CLASS="NAVHEADER"
CLASS="NAVHEADER"
><TABLE
><TABLE
SUMMARY="Header navigation table"
SUMMARY="Header navigation table"
WIDTH="100%"
WIDTH="100%"
BORDER="0"
BORDER="0"
CELLPADDING="0"
CELLPADDING="0"
CELLSPACING="0"
CELLSPACING="0"
><TR
><TR
><TH
><TH
COLSPAN="3"
COLSPAN="3"
ALIGN="center"
ALIGN="center"
>eCos User Guide</TH
>eCos User Guide</TH
></TR
></TR
><TR
><TR
><TD
><TD
WIDTH="10%"
WIDTH="10%"
ALIGN="left"
ALIGN="left"
VALIGN="bottom"
VALIGN="bottom"
><A
><A
HREF="sample-twothreads.html"
HREF="sample-twothreads.html"
ACCESSKEY="P"
ACCESSKEY="P"
>Prev</A
>Prev</A
></TD
></TD
><TD
><TD
WIDTH="80%"
WIDTH="80%"
ALIGN="center"
ALIGN="center"
VALIGN="bottom"
VALIGN="bottom"
></TD
></TD
><TD
><TD
WIDTH="10%"
WIDTH="10%"
ALIGN="right"
ALIGN="right"
VALIGN="bottom"
VALIGN="bottom"
><A
><A
HREF="the-ecos-configuration-tool.html"
HREF="the-ecos-configuration-tool.html"
ACCESSKEY="N"
ACCESSKEY="N"
>Next</A
>Next</A
></TD
></TD
></TR
></TR
></TABLE
></TABLE
><HR
><HR
ALIGN="LEFT"
ALIGN="LEFT"
WIDTH="100%"></DIV
WIDTH="100%"></DIV
><DIV
><DIV
CLASS="CHAPTER"
CLASS="CHAPTER"
><H1
><H1
><A
><A
NAME="CLOCKS-AND-ALARM-HANDLERS">Chapter 14. More Features &#8212; Clocks and Alarm
NAME="CLOCKS-AND-ALARM-HANDLERS">Chapter 14. More Features &#8212; Clocks and Alarm
Handlers</H1
Handlers</H1
><P
><P
>If a program wanted to execute a task at a given time, or
>If a program wanted to execute a task at a given time, or
periodically, it could do it in an inefficient way by sitting in a
periodically, it could do it in an inefficient way by sitting in a
loop and checking the real-time clock to see if the proper amount of
loop and checking the real-time clock to see if the proper amount of
time has elapsed. But operating systems usually provide system calls
time has elapsed. But operating systems usually provide system calls
which allow the program to be informed at the desired time.</P
which allow the program to be informed at the desired time.</P
><P
><P
><SPAN
><SPAN
CLASS="PRODUCTNAME"
CLASS="PRODUCTNAME"
>eCos</SPAN
>eCos</SPAN
> provides a rich timekeeping formalism, involving
> provides a rich timekeeping formalism, involving
<SPAN
<SPAN
CLASS="emphasis"
CLASS="emphasis"
><I
><I
CLASS="EMPHASIS"
CLASS="EMPHASIS"
>counters</I
>counters</I
></SPAN
></SPAN
>, <SPAN
>, <SPAN
CLASS="emphasis"
CLASS="emphasis"
><I
><I
CLASS="EMPHASIS"
CLASS="EMPHASIS"
>clocks</I
>clocks</I
></SPAN
></SPAN
>,
>,
<SPAN
<SPAN
CLASS="emphasis"
CLASS="emphasis"
><I
><I
CLASS="EMPHASIS"
CLASS="EMPHASIS"
>alarms</I
>alarms</I
></SPAN
></SPAN
>, and <SPAN
>, and <SPAN
CLASS="emphasis"
CLASS="emphasis"
><I
><I
CLASS="EMPHASIS"
CLASS="EMPHASIS"
>timers</I
>timers</I
></SPAN
></SPAN
>.  The
>.  The
precise definition, relationship, and motivation of these features is
precise definition, relationship, and motivation of these features is
beyond the scope of this tutorial, but these examples illustrate how
beyond the scope of this tutorial, but these examples illustrate how
to set up basic periodic tasks.</P
to set up basic periodic tasks.</P
><P
><P
>Alarms are events that happen at
>Alarms are events that happen at
a given time, either once or periodically. A thread associates an
a given time, either once or periodically. A thread associates an
alarm handling function with the alarm, so that the function will
alarm handling function with the alarm, so that the function will
be invoked every time the alarm &#8220;goes off&#8221;.</P
be invoked every time the alarm &#8220;goes off&#8221;.</P
><DIV
><DIV
CLASS="SECT1"
CLASS="SECT1"
><H1
><H1
CLASS="SECT1"
CLASS="SECT1"
><A
><A
NAME="SAMPLE-ALARMS">A Sample Program with Alarms</H1
NAME="SAMPLE-ALARMS">A Sample Program with Alarms</H1
><P
><P
><TT
><TT
CLASS="FILENAME"
CLASS="FILENAME"
>simple-alarm.c</TT
>simple-alarm.c</TT
> (in
> (in
the examples directory) is a short program that creates a thread that
the examples directory) is a short program that creates a thread that
creates an alarm. The alarm is handled by the function
creates an alarm. The alarm is handled by the function
<TT
<TT
CLASS="FUNCTION"
CLASS="FUNCTION"
>test_alarm_func()</TT
>test_alarm_func()</TT
>, which sets a global
>, which sets a global
variable. When the main thread of execution sees that the variable has
variable. When the main thread of execution sees that the variable has
changed, it prints a message.</P
changed, it prints a message.</P
><DIV
><DIV
CLASS="EXAMPLE"
CLASS="EXAMPLE"
><A
><A
NAME="AEN910"><P
NAME="AEN910"><P
><B
><B
>Example 14-1. A sample program that creates an alarm</B
>Example 14-1. A sample program that creates an alarm</B
></P
></P
><TABLE
><TABLE
BORDER="5"
BORDER="5"
BGCOLOR="#E0E0F0"
BGCOLOR="#E0E0F0"
WIDTH="70%"
WIDTH="70%"
><TR
><TR
><TD
><TD
><PRE
><PRE
CLASS="PROGRAMLISTING"
CLASS="PROGRAMLISTING"
>/* this is a very simple program meant to demonstrate
>/* this is a very simple program meant to demonstrate
 a basic use of time, alarms and alarm-handling functions  in eCos */
 a basic use of time, alarms and alarm-handling functions  in eCos */
 
 
#include &lt;cyg/kernel/kapi.h&#62;
#include &lt;cyg/kernel/kapi.h&#62;
 
 
#include &lt;stdio.h&#62;
#include &lt;stdio.h&#62;
 
 
#define NTHREADS 1
#define NTHREADS 1
#define STACKSIZE 4096
#define STACKSIZE 4096
 
 
static cyg_handle_t thread[NTHREADS];
static cyg_handle_t thread[NTHREADS];
 
 
static cyg_thread thread_obj[NTHREADS];
static cyg_thread thread_obj[NTHREADS];
static char stack[NTHREADS][STACKSIZE];
static char stack[NTHREADS][STACKSIZE];
 
 
static void alarm_prog( cyg_addrword_t data );
static void alarm_prog( cyg_addrword_t data );
 
 
/* we install our own startup routine which sets up
/* we install our own startup routine which sets up
  threads and starts the scheduler */
  threads and starts the scheduler */
void cyg_user_start(void)
void cyg_user_start(void)
{
{
 cyg_thread_create(4, alarm_prog, (cyg_addrword_t) 0,
 cyg_thread_create(4, alarm_prog, (cyg_addrword_t) 0,
        "alarm_thread", (void *) stack[0],
        "alarm_thread", (void *) stack[0],
        STACKSIZE, &amp;thread[0], &amp;thread_obj[0]);
        STACKSIZE, &amp;thread[0], &amp;thread_obj[0]);
 cyg_thread_resume(thread[0]);
 cyg_thread_resume(thread[0]);
}
}
 
 
/* we need to declare the alarm handling function (which is
/* we need to declare the alarm handling function (which is
 defined below), so that we can pass it to  cyg_alarm_initialize() */
 defined below), so that we can pass it to  cyg_alarm_initialize() */
cyg_alarm_t test_alarm_func;
cyg_alarm_t test_alarm_func;
 
 
/* alarm_prog() is a thread which sets up an alarm which is then
/* alarm_prog() is a thread which sets up an alarm which is then
 handled by test_alarm_func() */
 handled by test_alarm_func() */
static void alarm_prog(cyg_addrword_t data)
static void alarm_prog(cyg_addrword_t data)
{
{
 cyg_handle_t test_counterH, system_clockH, test_alarmH;
 cyg_handle_t test_counterH, system_clockH, test_alarmH;
 cyg_tick_count_t ticks;
 cyg_tick_count_t ticks;
 cyg_alarm test_alarm;
 cyg_alarm test_alarm;
 unsigned how_many_alarms = 0, prev_alarms = 0, tmp_how_many;
 unsigned how_many_alarms = 0, prev_alarms = 0, tmp_how_many;
 
 
 system_clockH = cyg_real_time_clock();
 system_clockH = cyg_real_time_clock();
 cyg_clock_to_counter(system_clockH, &amp;test_counterH);
 cyg_clock_to_counter(system_clockH, &amp;test_counterH);
 cyg_alarm_create(test_counterH, test_alarm_func,
 cyg_alarm_create(test_counterH, test_alarm_func,
        (cyg_addrword_t) &amp;how_many_alarms,
        (cyg_addrword_t) &amp;how_many_alarms,
        &amp;test_alarmH, &amp;test_alarm);
        &amp;test_alarmH, &amp;test_alarm);
 cyg_alarm_initialize(test_alarmH, cyg_current_time()+200, 200);
 cyg_alarm_initialize(test_alarmH, cyg_current_time()+200, 200);
 
 
 /* get in a loop in which we read the current time and
 /* get in a loop in which we read the current time and
    print it out, just to have something scrolling by */
    print it out, just to have something scrolling by */
 for (;;) {
 for (;;) {
   ticks = cyg_current_time();
   ticks = cyg_current_time();
   printf("Time is %llu\n", ticks);
   printf("Time is %llu\n", ticks);
   /* note that we must lock access to how_many_alarms, since the
   /* note that we must lock access to how_many_alarms, since the
   alarm handler might change it. this involves using the
   alarm handler might change it. this involves using the
   annoying temporary variable tmp_how_many so that I can keep the
   annoying temporary variable tmp_how_many so that I can keep the
   critical region short */
   critical region short */
   cyg_scheduler_lock();
   cyg_scheduler_lock();
   tmp_how_many = how_many_alarms;
   tmp_how_many = how_many_alarms;
   cyg_scheduler_unlock();
   cyg_scheduler_unlock();
   if (prev_alarms != tmp_how_many) {
   if (prev_alarms != tmp_how_many) {
     printf(" --- alarm calls so far: %u\n", tmp_how_many);
     printf(" --- alarm calls so far: %u\n", tmp_how_many);
     prev_alarms = tmp_how_many;
     prev_alarms = tmp_how_many;
   }
   }
   cyg_thread_delay(30);
   cyg_thread_delay(30);
 }
 }
}
}
 
 
/* test_alarm_func() is invoked as an alarm handler, so
/* test_alarm_func() is invoked as an alarm handler, so
   it should be quick and simple. in this case it increments
   it should be quick and simple. in this case it increments
   the data that is passed to it. */
   the data that is passed to it. */
void test_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data)
void test_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data)
{
{
 ++*((unsigned *) data);
 ++*((unsigned *) data);
}</PRE
}</PRE
></TD
></TD
></TR
></TR
></TABLE
></TABLE
></DIV
></DIV
><P
><P
>When you run this program (by typing <B
>When you run this program (by typing <B
CLASS="COMMAND"
CLASS="COMMAND"
>continue</B
>continue</B
> at
> at
the (<SPAN
the (<SPAN
CLASS="emphasis"
CLASS="emphasis"
><I
><I
CLASS="EMPHASIS"
CLASS="EMPHASIS"
>gdb</I
>gdb</I
></SPAN
></SPAN
>) prompt) the output should look like
>) prompt) the output should look like
this:</P
this:</P
><TABLE
><TABLE
BORDER="5"
BORDER="5"
BGCOLOR="#E0E0F0"
BGCOLOR="#E0E0F0"
WIDTH="70%"
WIDTH="70%"
><TR
><TR
><TD
><TD
><PRE
><PRE
CLASS="SCREEN"
CLASS="SCREEN"
>Starting program: <TT
>Starting program: <TT
CLASS="REPLACEABLE"
CLASS="REPLACEABLE"
><I
><I
>BASE_DIR</I
>BASE_DIR</I
></TT
></TT
>/examples/simple-alarm.exe
>/examples/simple-alarm.exe
Time is 0
Time is 0
Time is 30
Time is 30
Time is 60
Time is 60
Time is 90
Time is 90
Time is 120
Time is 120
Time is 150
Time is 150
Time is 180
Time is 180
Time is 210
Time is 210
  --- alarm calls so far: 1
  --- alarm calls so far: 1
Time is 240
Time is 240
Time is 270
Time is 270
Time is 300
Time is 300
Time is 330
Time is 330
Time is 360
Time is 360
Time is 390
Time is 390
Time is 420
Time is 420
  --- alarm calls so far: 2
  --- alarm calls so far: 2
Time is 450
Time is 450
Time is 480</PRE
Time is 480</PRE
></TD
></TD
></TR
></TR
></TABLE
></TABLE
><DIV
><DIV
CLASS="NOTE"
CLASS="NOTE"
><BLOCKQUOTE
><BLOCKQUOTE
CLASS="NOTE"
CLASS="NOTE"
><P
><P
><B
><B
>Note: </B
>Note: </B
>When running in a simulator the  delays
>When running in a simulator the  delays
might be quite long. On a hardware board (where the clock speed is 100
might be quite long. On a hardware board (where the clock speed is 100
ticks/second) the delays should average to about 0.3 seconds (and 2
ticks/second) the delays should average to about 0.3 seconds (and 2
seconds between alarms). In simulation, the delay will depend on the
seconds between alarms). In simulation, the delay will depend on the
speed of the host processor and will almost always be much slower than
speed of the host processor and will almost always be much slower than
the actual board. You might want to reduce the delay parameter when
the actual board. You might want to reduce the delay parameter when
running in simulation.</P
running in simulation.</P
></BLOCKQUOTE
></BLOCKQUOTE
></DIV
></DIV
><P
><P
>Here are a few things you might notice about this program:</P
>Here are a few things you might notice about this program:</P
><P
><P
></P
></P
><UL
><UL
><LI
><LI
><P
><P
>It used the <TT
>It used the <TT
CLASS="FUNCTION"
CLASS="FUNCTION"
>cyg_real_time_clock()</TT
>cyg_real_time_clock()</TT
> function;
> function;
this always returns a handle to the default system real-time  clock. </P
this always returns a handle to the default system real-time  clock. </P
></LI
></LI
><LI
><LI
><P
><P
>Clocks are based on  counters, so the function <TT
>Clocks are based on  counters, so the function <TT
CLASS="FUNCTION"
CLASS="FUNCTION"
>cyg_alarm_create()</TT
>cyg_alarm_create()</TT
>
>
uses a counter handle. The program used the function
uses a counter handle. The program used the function
<TT
<TT
CLASS="FUNCTION"
CLASS="FUNCTION"
>cyg_clock_to_counter()</TT
>cyg_clock_to_counter()</TT
> to strip the clock handle
> to strip the clock handle
to the underlying counter handle. </P
to the underlying counter handle. </P
></LI
></LI
><LI
><LI
><P
><P
>Once the alarm is created it is
>Once the alarm is created it is
initialized with <TT
initialized with <TT
CLASS="FUNCTION"
CLASS="FUNCTION"
>cyg_alarm_initialize()</TT
>cyg_alarm_initialize()</TT
>, which
>, which
sets the time at which the alarm should go off, as well as the period
sets the time at which the alarm should go off, as well as the period
for repeating alarms. It is set to go off at the current time and
for repeating alarms. It is set to go off at the current time and
then to repeat every 200 ticks. </P
then to repeat every 200 ticks. </P
></LI
></LI
><LI
><LI
><P
><P
>The alarm handler function
>The alarm handler function
<TT
<TT
CLASS="FUNCTION"
CLASS="FUNCTION"
>test_alarm_func()</TT
>test_alarm_func()</TT
> conforms to the guidelines for
> conforms to the guidelines for
writing alarm handlers and other  delayed service routines: it does not invoke any
writing alarm handlers and other  delayed service routines: it does not invoke any
functions which might lock the scheduler.  This is discussed in detail
functions which might lock the scheduler.  This is discussed in detail
in the <I
in the <I
CLASS="CITETITLE"
CLASS="CITETITLE"
><SPAN
><SPAN
CLASS="PRODUCTNAME"
CLASS="PRODUCTNAME"
>eCos</SPAN
>eCos</SPAN
> Reference Manual</I
> Reference Manual</I
>, in the chapter
>, in the chapter
<I
<I
CLASS="CITETITLE"
CLASS="CITETITLE"
>The <SPAN
>The <SPAN
CLASS="PRODUCTNAME"
CLASS="PRODUCTNAME"
>eCos</SPAN
>eCos</SPAN
> Kernel</I
> Kernel</I
>.</P
>.</P
></LI
></LI
><LI
><LI
><P
><P
>There is a <SPAN
>There is a <SPAN
CLASS="emphasis"
CLASS="emphasis"
><I
><I
CLASS="EMPHASIS"
CLASS="EMPHASIS"
>critical region</I
>critical region</I
></SPAN
></SPAN
> in this program:
> in this program:
the variable <TT
the variable <TT
CLASS="LITERAL"
CLASS="LITERAL"
>how_many_alarms</TT
>how_many_alarms</TT
> is accessed in the
> is accessed in the
main thread of control and is also modified in the alarm handler. To
main thread of control and is also modified in the alarm handler. To
prevent a possible (though unlikely) race condition on this variable,
prevent a possible (though unlikely) race condition on this variable,
access to <TT
access to <TT
CLASS="LITERAL"
CLASS="LITERAL"
>how_many_alarms</TT
>how_many_alarms</TT
> in the principal thread
> in the principal thread
is protected by calls to <TT
is protected by calls to <TT
CLASS="FUNCTION"
CLASS="FUNCTION"
>cyg_scheduler_lock()</TT
>cyg_scheduler_lock()</TT
> and
> and
<TT
<TT
CLASS="FUNCTION"
CLASS="FUNCTION"
>cyg_scheduler_unlock()</TT
>cyg_scheduler_unlock()</TT
>. When the scheduler is
>. When the scheduler is
locked, the alarm handler will not be invoked, so the problem is
locked, the alarm handler will not be invoked, so the problem is
averted. </P
averted. </P
></LI
></LI
></UL
></UL
></DIV
></DIV
></DIV
></DIV
><DIV
><DIV
CLASS="NAVFOOTER"
CLASS="NAVFOOTER"
><HR
><HR
ALIGN="LEFT"
ALIGN="LEFT"
WIDTH="100%"><TABLE
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
SUMMARY="Footer navigation table"
WIDTH="100%"
WIDTH="100%"
BORDER="0"
BORDER="0"
CELLPADDING="0"
CELLPADDING="0"
CELLSPACING="0"
CELLSPACING="0"
><TR
><TR
><TD
><TD
WIDTH="33%"
WIDTH="33%"
ALIGN="left"
ALIGN="left"
VALIGN="top"
VALIGN="top"
><A
><A
HREF="sample-twothreads.html"
HREF="sample-twothreads.html"
ACCESSKEY="P"
ACCESSKEY="P"
>Prev</A
>Prev</A
></TD
></TD
><TD
><TD
WIDTH="34%"
WIDTH="34%"
ALIGN="center"
ALIGN="center"
VALIGN="top"
VALIGN="top"
><A
><A
HREF="ecos-user-guide.html"
HREF="ecos-user-guide.html"
ACCESSKEY="H"
ACCESSKEY="H"
>Home</A
>Home</A
></TD
></TD
><TD
><TD
WIDTH="33%"
WIDTH="33%"
ALIGN="right"
ALIGN="right"
VALIGN="top"
VALIGN="top"
><A
><A
HREF="the-ecos-configuration-tool.html"
HREF="the-ecos-configuration-tool.html"
ACCESSKEY="N"
ACCESSKEY="N"
>Next</A
>Next</A
></TD
></TD
></TR
></TR
><TR
><TR
><TD
><TD
WIDTH="33%"
WIDTH="33%"
ALIGN="left"
ALIGN="left"
VALIGN="top"
VALIGN="top"
>A Sample Program with Two Threads</TD
>A Sample Program with Two Threads</TD
><TD
><TD
WIDTH="34%"
WIDTH="34%"
ALIGN="center"
ALIGN="center"
VALIGN="top"
VALIGN="top"
><A
><A
HREF="user-guide-programming.html"
HREF="user-guide-programming.html"
ACCESSKEY="U"
ACCESSKEY="U"
>Up</A
>Up</A
></TD
></TD
><TD
><TD
WIDTH="33%"
WIDTH="33%"
ALIGN="right"
ALIGN="right"
VALIGN="top"
VALIGN="top"
>The eCos Configuration Tool</TD
>The eCos Configuration Tool</TD
></TR
></TR
></TABLE
></TABLE
></DIV
></DIV
></BODY
></BODY
></HTML
></HTML
 
 

powered by: WebSVN 2.1.0

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