SIMD-VITERBI 3
NAME
create_viterbi27, set_viterbi27_polynomial, init_viterbi27, update_viterbi27_blk,
chainback_viterbi27, delete_viterbi27,
create_viterbi29, set_viterbi_29_polynomial, init_viterbi29, update_viterbi29_blk,
chainback_viterbi29, delete_viterbi29,
create_viterbi39, set_viterbi_39_polynomial, init_viterbi39, update_viterbi39_blk,
chainback_viterbi39, delete_viterbi39,
create_viterbi615, set_viterbi615_polynomial, init_viterbi615, update_viterbi615_blk,
chainback_viterbi615, delete_viterbi615 - IA32 SIMD-assisted Viterbi decoders
SYNOPSIS
#include "fec.h" void *create_viterbi27(int blocklen); void set_viterbi27_polynomial(int polys[2]); int init_viterbi27(void *vp,int starting_state); int update_viterbi27_blk(void *vp,unsigned char syms[],int nbits); int chainback_viterbi27(void *vp, unsigned char *data,unsigned int nbits,unsigned int endstate); void delete_viterbi27(void *vp);
void *create_viterbi29(int blocklen); void set_viterbi29_polynomial(int polys[2]); int init_viterbi29(void *vp,int starting_state); int update_viterbi29_blk(void *vp,unsigned char syms[],int nbits); int chainback_viterbi29(void *vp, unsigned char *data,unsigned int nbits,unsigned int endstate); void delete_viterbi29(void *vp);
void *create_viterbi39(int blocklen); void set_viterbi39_polynomial(int polys[3]); int init_viterbi39(void *vp,int starting_state); int update_viterbi39_blk(void *vp,unsigned char syms[],int nbits); int chainback_viterbi39(void *vp, unsigned char *data,unsigned int nbits,unsigned int endstate); void delete_viterbi39(void *vp);
void *create_viterbi615(int blocklen); void set_viterbi615_polynomial(int polys[6]); int init_viterbi615(void *vp,int starting_state); int update_viterbi615_blk(void *vp,unsigned char syms[],int nbits); int chainback_viterbi615(void *vp, unsigned char *data,unsigned int nbits,unsigned int endstate); void delete_viterbi615(void *vp);
DESCRIPTION
These functions implement high performance Viterbi decoders for four
convolutional codes: a rate 1/2 constraint length 7 (k=7) code
("viterbi27"), a rate 1/2 k=9 code ("viterbi29"),
a rate 1/3 k=9 code ("viterbi39") and a rate 1/6 k=15 code ("viterbi615").
The decoders use the Intel IA32 or PowerPC SIMD instruction sets, if available, to improve
decoding speed.
On the IA32 there are three different SIMD instruction sets. The first
and most common is MMX, introduced on later Intel Pentiums and then on
the Intel Pentium II and most Intel clones (AMD K6, Transmeta Crusoe,
etc). SSE was introduced on the Pentium III and later implemented in
the AMD Athlon 4 (AMD calls it "3D Now! Professional"). Most
recently, SSE2 was introduced in the Intel Pentium 4, and has been
adopted by more recent AMD CPUs. The presence of SSE2 implies the
existence of SSE, which in turn implies MMX.
Altivec is the PowerPC SIMD instruction set. It is roughly comparable
to SSE2. Altivec was introduced to the general public in the Apple
Macintosh G4; it is also present in the G5. Altivec is actually a
Motorola trademark; Apple calls it "Velocity Engine" and IBM calls it
"VMX". All refer to the same thing.
When built for the IA32 or PPC architectures, the functions
automatically use the most powerful SIMD instruction set available. If
no SIMD instructions are available, or if the library is built for a
non-IA32, non-PPC machine, a portable C version is executed
instead.
USAGE
Four versions of each function are provided, one for each code.
In the following discussion, change "viterbi" to "viterbi27", "viterbi29", "viterbi39"
or "viterbi615" as desired.
Before Viterbi decoding can begin, an instance must first be created with
create_viterbi(). This function creates and returns a pointer to
an internal control structure
containing the path metrics and the branch
decisions. create_viterbi() takes one argument that gives the
length of the data block in bits. You must not attempt to
decode a block longer than the length given to create_viterbi().
Before decoding a new frame,
init_viterbi() must be called to reset the decoder state.
It accepts the instance pointer returned by
create_viterbi() and the initial starting state of the
convolutional encoder (usually 0). If the initial starting state is unknown or
incorrect, the decoder will still function but the decoded data may be
incorrect at the start of the block.
Blocks of received symbols are processed with calls to
update_viterbi_blk(). The nbits parameter specifies the
number of data bits (not channel symbols) represented by the
syms buffer. (For rate 1/2 codes, the number of symbols in
syms is twice nbits, and so on.)
Each symbol is expected to range
from 0 through 255, with 0 corresponding to a "strong 0" and 255
corresponding to a "strong 1". The caller is responsible for
determining the proper pairing of input symbols (commonly known as
decoder symbol phasing).
At the end of the block, the data is recovered with a call to
chainback_viterbi(). The arguments are the pointer to the
decoder instance, a pointer to a user-supplied buffer into which the
decoded data is to be written, the number of data bits (not bytes)
that are to be decoded, and the terminal state of the convolutional
encoder at the end of the frame (usually 0). If the terminal state is
incorrect or unknown, the decoded data bits at the end of the frame
may be unreliable. The decoded data is written in big-endian order,
i.e., the first bit in the frame is written into the high order bit of
the first byte in the buffer. If the frame is not an integral number
of bytes long, the low order bits of the last byte in the frame will
be unused.
Note that the decoders assume the use of a tail, i.e., the encoding
and transmission of a sufficient number of padding bits beyond the end
of the user data to force the convolutional encoder into the known
terminal state given to chainback_viterbi(). The tail is
always one bit less than the constraint length of the code, so the k=7
code uses 6 tail bits (12 tail symbols), the k=9 code uses 8 tail bits
(16 tail symbols) and the k=15 code uses 14 tail bits (84 tail
symbols).
The tail bits are not included in the length arguments to
create_viterbi() and chainback_viterbi(). For example, if
the block contains 1000 user bits, then this would be the length
parameter given to create_viterbi27() and
chainback_viterbi27(), and update_viterbi27_blk() would be called
with a total of 2012 symbols - the last 12 encoded symbols
representing the tail bits.
After the call to chainback_viterbi(), the decoder may be reset
with a call to init_viterbi() and another block can be decoded.
Alternatively, delete_viterbi() can be called to free all resources
used by the Viterbi decoder.
The set_viterbi_polynomial() function allows use of other than the default
code generator polynomials. Although only one set of polynomials are generally
used with each code, there can are different conventions as to their order and
symbol polarity, and these functions simplifies their use.
The default polynomials for the viterbi27 routes
are those of the NASA-JPL convention without symbol inversion.
The NASA-JPL convention normally inverts the first symbol.
The CCSDS/NASA-GSFC convention swaps the two symbols and inverts the second.
To set the NASA-JPL convention with symbol inversion:
int polys[2] = { -V27POLYA,V27POLYB }; set_viterbi27_polynomial(polys);and to set the CCSDS convention with symbol inversion:
int polys[2] = { V27POLYB,-V27POLYA }; set_viterbi27_polynomial(polys);The default polynomials for the viterbi615 routines are those used by the Cassini spacecraft without symbol inversion. Mars Pathfinder (MPF) and STEREO swap the third and fourth polynomials. Both conventions invert the first, third and fifth symbols. Refer to fec.h for the polynomial constant definitions. To set the Cassini convention with symbol inversion, do the following:
int polys[6] = { -V615POLYA,V615POLYB,-V615POLYC,V615POLYD,-V615POLYE,V615POLYF }; set_viterbi615_polynomial(polys);and to set the MPF/STEREO convention with symbol inversion:
int polys[6] = { -V615POLYA,V615POLYB,-V615POLYD,V615POLYC,-V615POLYE,V615POLYF }; set_viterbi615_polynomial(polys);For performance reasons, calling this function changes the code generator polynomials for all instances of corresponding Viterbi decoder, including those already created.
ERROR PERFORMANCE
These decoders have all been extensively tested and found to provide
performance consistent with that expected for soft-decision Viterbi
decoding with 8-bit symbols.
Due to internal differences, the implementations
vary slightly in error performance. In
general, the portable C versions exhibit the best error performance
because they use full-sized branch metrics, and the MMX versions
exhibit the worst because they use 8-bit branch metrics with modulo
comparisons. The SSE, SSE2 and Altivec implementations of the r=1/2 k=7 and
r=1/2 k=9 codes use unsigned
8-bit branch metrics, and are almost as good as the C versions. The
r=1/3 k=9 and r=1/6 k=15 codes are implemented with 16-bit path metrics in all SIMD
versions.
DIRECT ACCESS TO SPECIFIC FUNCTION VERSIONS
Calling the functions listed above automatically calls the appropriate
version of the function depending on the CPU type and available SIMD
instructions. A particular version can also be called directly by
appending the appropriate suffix to the function name. The available
suffixes are "_mmx", "_sse", "_sse2", "_av" and "_port", for the MMX,
SSE, SSE2, Altivec and portable versions, respectively. For example,
the SSE2 version of the update_viterbi27_blk() function can be invoked
as update_viterbi27_blk_sse2().
Naturally, the _av functions are only available on the PowerPC and the
_mmx, _sse and _sse2 versions are only available on IA-32. Calling
a SIMD-enabled function on a CPU that doesn't support the appropriate
set of instructions will result in an illegal instruction exception.
RETURN VALUES
create_viterbi returns a pointer to the structure containing
the decoder state.
The other functions return -1 on error, 0 otherwise.
AUTHOR & COPYRIGHT
Phil Karn, KA9Q (karn@ka9q.net)
LICENSE
This software may be used under the terms of the GNU Limited General Public License (LGPL).