📄 hal.sgml
字号:
situations where a wait/timeout loop would otherwise be used. Since it
may disable interrupts, and is implemented by busy waiting, it should
not be used in code that is sensitive to interrupt or context switch
latencies.
</para>
</section>
<!-- =================================================================== -->
<section>
<title>Clock Frequency Definition</title>
<programlisting width=72>
CYGNUM_HAL_RTC_NUMERATOR
CYGNUM_HAL_RTC_DENOMINATOR
CYGNUM_HAL_RTC_PERIOD
</programlisting>
<para>
These macros are defined in the CDL for each platform and supply the
necessary parameters to specify the frequency at which the clock
interrupts. These parameters are usually found in the CDL definitions
for the target platform, or in some cases the CPU variant.
</para>
<para>
<literal>CYGNUM_HAL_RTC_NUMERATOR</literal> and
<literal>CYGNUM_HAL_RTC_DENOMINATOR</literal> specify the resolution
of the clock interrupt. This resolution involves two separate values,
the numerator and the denominator. The result of dividing the
numerator by the denominator should correspond to the number of
nanoseconds between clock interrupts. For example a numerator of
1000000000 and a denominator of 100 means that there are 10000000
nanoseconds (or 10 milliseconds) between clock interrupts. Expressing
the resolution as a fraction minimizes clock drift even for
frequencies that cannot be expressed as a simple integer. For example
a frequency of 60Hz corresponds to a clock resolution of
16666666.66... nanoseconds. This can be expressed accurately as
1000000000 over 60.
</para>
<para>
<literal>CYGNUM_HAL_RTC_PERIOD</literal> specifies the exact value
used to initialize the clock hardware, it is the value passed as a
parameter to <literal>HAL_CLOCK_INITIALIZE()</literal> and
<literal>HAL_CLOCK_RESET()</literal>. The exact meaning of the value
and the range of legal values therefore depends on the target
hardware, and the hardware documentation should be consulted for
further details.
</para>
<para>
The default values for these macros in all HALs are calculated to give
a clock interrupt frequency of 100Hz, or 10ms between interrupts. To
change the clock frequency, the period needs to be changed, and the
resolution needs to be adjusted accordingly. As an example consider
the i386 PC target. The default values for these macros are:
</para>
<programlisting width=72>
CYGNUM_HAL_RTC_NUMERATOR 1000000000
CYGNUM_HAL_RTC_DENOMINATOR 100
CYGNUM_HAL_RTC_PERIOD 11932
</programlisting>
<para>
To change to, say, a 200Hz clock the period needs to be halved to
5966, and to compensate the denominator needs to be doubled to 200. To
change to a 1KHz interrupt rate change the period to 1193 and the
denominator to 1000.
</para>
<para>
Some HALs make this process a little easier by deriving the period
arithmetically from the denominator. This calculation may also involve
the CPU clock frequency and possibly other factors. For example in the
ARM AT91 variant HAL the period is defined by the following
expression:
</para>
<programlisting width=72>
((CYGNUM_HAL_ARM_AT91_CLOCK_SPEED/32) / CYGNUM_HAL_RTC_DENOMINATOR)
</programlisting>
<para>
In this case it is not necessary to change the period at all, just
change the denominator to select the desired clock frequency. However,
note that for certain choices of frequency, rounding errors in this
calculation may result in a small clock drift over time. This is
usually negligible, but if perfect accuracy is required, it may be
necessary to adjust the frequency or period by hand.
</para>
</section>
</section>
<!-- }}} -->
<!-- {{{ Input and Output -->
<SECTION id="hal-input-and-output">
<TITLE>HAL I/O</TITLE>
<PARA>
This section contains definitions for supporting access
to device control registers in an architecture neutral
fashion.
</PARA>
<para>
These definitions are normally found in the header file
<FILENAME>cyg/hal/hal_io.h</FILENAME>. This file itself contains
macros that are generic to the architecture. If there are variant or
platform specific IO access macros then these will be found in
<filename>cyg/hal/var_io.h</filename> and
<filename>cyg/hal/plf_io.h</filename> in the variant or platform HALs
respectively. These files are include automatically by this header, so
need not be included explicitly.
</para>
<para>
This header (or more likely <filename>cyg/hal/plf_io.h</filename>) also
defines the PCI access macros. For more information on these see <xref
linkend="pci-library-reference">.
</para>
<!-- =================================================================== -->
<SECTION>
<TITLE>Register address</TITLE>
<PROGRAMLISTING>
HAL_IO_REGISTER
</PROGRAMLISTING>
<PARA>
This type is used to store the address of an I/O register. It will
normally be a memory address, an integer port address or an offset
into an I/O space. More complex architectures may need to code an
address space plus offset pair into a single word, or may represent it
as a structure.
</PARA>
<PARA>
Values of variables and constants of this type will usually be
supplied by configuration mechanisms or in target specific headers.
</PARA>
</SECTION>
<!-- =================================================================== -->
<SECTION>
<TITLE>Register read</TITLE>
<PROGRAMLISTING>
HAL_READ_XXX( register, value )
HAL_READ_XXX_VECTOR( register, buffer, count, stride )
</PROGRAMLISTING>
<PARA>
These macros support the reading of I/O registers in various
sizes. The <replaceable>XXX</replaceable> component of the name may be
<literal>UINT8</literal>, <literal>UINT16</literal>,
<literal>UINT32</literal>.
</PARA>
<PARA>
<FUNCTION>HAL_READ_XXX()</FUNCTION> reads the appropriately sized
value from the register and stores it in the variable passed as the
second argument.
</PARA>
<PARA>
<FUNCTION>HAL_READ_XXX_VECTOR()</FUNCTION> reads
<parameter>count</parameter> values of the appropriate size into
<parameter>buffer</parameter>. The <parameter>stride</parameter>
controls how the pointer advances through the register space. A stride
of zero will read the same register repeatedly, and a stride of one
will read adjacent registers of the given size. Greater strides will
step by larger amounts, to allow for sparsely mapped registers for
example.</PARA>
</SECTION>
<!-- =================================================================== -->
<SECTION>
<TITLE>Register write</TITLE>
<PROGRAMLISTING>
HAL_WRITE_XXX( register, value )
HAL_WRITE_XXX_VECTOR( register, buffer,count, stride )
</PROGRAMLISTING>
<PARA>
These macros support the writing of I/O registers in various
sizes. The <replaceable>XXX</replaceable> component of the name may be
<LITERAL>UINT8</LITERAL>, <LITERAL>UINT16</LITERAL>,
<LITERAL>UINT32</LITERAL>.
</PARA>
<PARA>
<FUNCTION>HAL_WRITE_XXX()</FUNCTION> writes
the appropriately sized value from the variable passed as the second argument
stored it in the register.</PARA>
<PARA><FUNCTION>HAL_WRITE_XXX_VECTOR()</FUNCTION> writes
<parameter>count</parameter> values of the appropriate size from <parameter>
buffer</parameter>. The <parameter>stride</parameter> controls
how the pointer advances through the register space. A stride of
zero will write the same register repeatedly, and a stride of one
will write adjacent registers of the given size. Greater strides
will step by larger amounts, to allow for sparsely mapped registers
for example.</PARA>
</SECTION>
</SECTION>
<!-- }}} -->
<!-- {{{ Cache Control -->
<SECTION id="hal-cache-control">
<TITLE>Cache Control</TITLE>
<PARA>This section contains definitions for supporting control
of the caches on the CPU.
</PARA>
<para>
These definitions are usually found in the header file
<FILENAME>cyg/hal/hal_cache.h</FILENAME>. This file may be defined in
the architecture, variant or platform HAL, depending on where the
caches are implemented for the target. Often there will be a generic
implementation of the cache control macros in the architecture HAL
with the ability to override or undefine them in the variant or
platform HAL. Even when the implementation of the cache macros is in
the architecture HAL, the cache dimensions will be defined in the
variant or platform HAL. As with other files, the variant or platform
specific definitions are usually found in
<filename>cyg/hal/var_cache.h</filename> and
<filename>cyg/hal/plf_cache.h</filename> respectively. These files
are include automatically by this header, so need not be included
explicitly.
</para>
<PARA>
There are versions of the macros defined here for both the Data and
Instruction caches. these are distinguished by the use of either
<literal>DCACHE</literal> or <literal>ICACHE</literal> in the macro
names. Some architectures have a unified cache, where both data and
instruction share the same cache. In these cases the control macros
use <literal>UCACHE</literal> and the <literal>DCACHE</literal> and
<literal>ICACHE</literal> macros will just be calls to the
<literal>UCACHE</literal> version. In the following descriptions,
<literal>XCACHE</literal> is used to stand for any of these. Where
there are issues specific to a particular cache, this will be
explained in the text.
</PARA>
<PARA>
There might be target specific restrictions on the use of some of the
macros which it is the user's responsibility to comply with. Such
restrictions are documented in the header file with the macro
definition.
</PARA>
<PARA>
Note that destructive cache macros should be used with caution.
Preceding a cache invalidation with a cache synchronization is not
safe in itself since an interrupt may happen after the synchronization
but before the invalidation. This might cause the state of dirty data
lines created during the interrupt to be lost.
</PARA>
<PARA>
Depending on the architecture's capabilities, it may be possible to
temporarily disable the cache while doing the synchronization and
invalidation which solves the problem (no new data would be cached
during an interrupt). Otherwise it is necessary to disable interrupts
while manipulating the cache which may take a long time.
</PARA>
<PARA>
Some platform HALs now support a pair of cache state query
macros: <function>HAL_ICACHE_IS_ENABLED( x )</function> and
<function>HAL_DCACHE_IS_ENABLED( x )</function> which set the argument
to true if the instruction or data cache is enabled,
respectively. Like most cache control macros, these are optional,
because the capabilities of different targets and boards can vary
considerably. Code which uses them, if it is to be considered
portable, should test for their existence first by means of
<literal>#ifdef</literal>. Be sure to include
<filename><cyg/hal/hal_cache.h></filename> in order to do this
test and (maybe) use the macros.
</PARA>
<!-- =================================================================== -->
<SECTION>
<TITLE>Cache Dimensions</TITLE>
<PROGRAMLISTING>
HAL_XCACHE_SIZE
HAL_XCACHE_LINE_SIZE
HAL_XCACHE_WAYS
HAL_XCACHE_SETS
</PROGRAMLISTING>
<PARA>
These macros define the size and dimensions of the Instruction
and Data caches.
</PARA>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>HAL_XCACHE_SIZE </TERM>
<LISTITEM>
<PARA>Defines the total size of the cache in bytes.</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>HAL_XCACHE_LINE_SIZE </TERM>
<LISTITEM>
<PARA>Defines the cache line size in bytes.</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>HAL_XCACHE_WAYS </TERM>
<LISTITEM>
<PARA>
Defines the number of ways in each set and defines its level
of associativity. This would be 1 for a direct mapped
cache, 2 for a 2-way cache, 4 for 4-way and so on.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>HAL_XCACHE_SETS </TERM>
<LISTITEM>
<PARA>
Defines the number of sets in the cache, and is calculated from
the previous values.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</SECTION>
<!-- =================================================================== -->
<SECTION>
<TITLE>Global Cache Control</TITLE>
<PROGRAMLISTING>
HAL_XCACHE_ENABLE()
HAL_XCACHE_DISABLE()
HAL_XCACHE_INVALIDATE_ALL()
HAL_XCACHE_SYNC()
HAL_XCACHE_BURST_SIZE( size )
HAL_DCACHE_WRITE_MODE( mode )
HAL_XCACHE_LOCK( base, size )
HAL_XCACHE_UNLOCK( base, size )
HAL_XCACHE_UNLOCK_ALL()
</PROGRAMLISTING>
<PARA>
These macros affect the state of the entire cache, or a large part of
it.
</PARA>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>HAL_XCACHE_ENABLE() and HAL_XCACHE_DISABLE()</TERM>
<LISTITEM>
<PARA>Enable and disable the cache.</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>HAL_XCACHE_INVALIDATE_ALL()</TERM>
<LISTITEM>
<PARA>
Causes the entire contents of the cache to be invalidated.
Depending on the hardware, this may require the cache to be disabled
during the invalidation process. If so, the implementation must
use <function>HAL_XCACHE_IS_ENABLED()</function> to save and
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -