NOTICE: The Processors Wiki will End-of-Life on January 15, 2021. It is recommended to download any files or other content you may need that are hosted on processors.wiki.ti.com. The site is now set to read only.
Byte Accesses with the C28x CPU
Contents
Introduction[edit]
The C28x is a 16-bit addressable CPU. That is, each unique address identifies 16-bits of data. 16-bit and 32-bit reads as well as writes are easily achieved via MOV and MOVL instructions. To access 8-bit data, special MOVB instructions are used. These instructions can access either the LSB or the MSB of the 16-bit word.
This article describes how these special instructions can be accessed when writing code in C or C++.
Other Resources[edit]
- Reference Guides
Byte Accesses With the C28x Compiler[edit]
The TMS320C28x byte is 16 Bits. By ANSI/ISO C definition, the sizeof operator yields the number of bytes required to store an object. ANSI/ISO further stipulates that when sizeof is applied to char, the result is 1. Since the TMS320C28x char is 16 bits (to make it separately addressable), a byte is also 16 bits.
This yields results you may not expect; for example, size of (int) = = 1 (not 2). It should also be noted that contrary to common usage, a byte is not defined as 8 bits. A byte is defined as the unit of data capable of holding a single character on any given machine. Hence, if the term "byte" is used on C2000 it refers to 16 bits. In summary: TMS320C28x bytes and words are equivalent (16 bits).
To access data in increments of 8 bits, use the __byte() intrinsic described in the TMS320C28x Optimizing C/C++ Compiler User's Guide (spru514)
Using the __byte Intrinsic[edit]
What are Intrinsics?[edit]
The C28x compiler recognizes a number of intrinsic operators. Intrinsics allow you to express the meaning of certain assembly statements that would otherwise be cumbersome or inexpressible in C/C++. Intrinsics are used like functions; you can use C/C++ variables with these intrinsics, just as you would with any normal function.
The intrinsics are specified with a leading underscore, and are accessed by calling them as you do a function. Available intrinsics are documented in the TMS320C28x Optimizing C/C++ Compiler User's Guide (spru514). In addition, consult the release notes for your compiler to see if new intrinsics have been added since the documentation was last updated.
The __byte() Intrinsic[edit]
- Prototype int __&byte(int *array, unsigned int byte_index);
- Generated Assembly:
- If the operation is a write: MOVB array[byte_index].LSB,
- If the operation is a read: MOVB dst, array[byte_index].LSB
Example 1[edit]
The following example shows how the compiler will translate the __byte intrinsic to a MOVB.LSB operation.
<syntaxhighlight lang='c'>
//
// Example code to show the use of the __byte C28x Compiler intrinsic
//
int16 MyArray[20];
int16 Val;
int16 Read1;
int16 Read2;
int16 Read3;
int16 Read4;
void main(void)
{
// Note: - means value was unchanged // from the previous state // __byte(MyArray,0) = 0x00; // MyArray[0] = 0x--00 __byte(MyArray,1) = 0x11; // MyArray[0] = 0x1100 __byte(MyArray,2) = 0x22; // MyArray[1] = 0x--22 __byte(MyArray,3) = 0x33; // MyArray[1] = 0x3322 __byte(MyArray,4) = 0x44; // MyArray[2] = 0x--44 __byte(MyArray,5) = 0x55; // MyArray[2] = 0x5544
__byte(&Val,0) = 0x66; // Val1 = 0x--66 __byte(&Val,1) = 0x77; // Val1 = 0x7766
Read1 = __byte(MyArray,2); // Read1 = 0x0022 (note: clears upper byte) Read2 = __byte(MyArray,5); // Read2 = 0x0055 (note: clears upper byte)
Read3 = __mov_byte(MyArray,4); // Read3 = 0x0044 (note: clears upper byte) Read4 = __mov_byte(MyArray,5); // Read4 = 0x0055 (note: clears upper byte)
... </syntaxhighlight>
Execution of this code will change memory contents as shown below:
Example 2[edit]
The following example illustrates how __byte can be used on the left-hand side to set values. This is the reason it returns a reference.
<syntaxhighlight lang="c">
- include <stdio.h>
int array[3] = { 0xaaaa, 0xbbbb, 0xcccc };
void main() {
int i;
__byte(array, 0) = 0;
for (i=0;i<3;i++) printf("%x\n", array[i]);
for (i=0;i<6;i++) printf("%x\n", __mov_byte(array, i));
} </syntaxhighlight>
Byte Addressing Modes[edit]
For the most part you do not need to worry about the addressing modes when using the intrinsics. It is useful to understand if you are looking at the generated assembly code or writing assembly code from scratch.
Example 1 shown in the previous section generates the following assembly code:
The instructions generated by the compiler follow the byte addressing mode rules shown below. More detail and additional forms of MOVB can be found in the TMS320C28x CPU and Instruction Set Reference Guide (spru430).
<syntaxhighlight lang='c'>
Instruction: MOVB AX.LSB, loc16 Offset: AR0, AR1 or 3-bit value
if( loc16 == *+XARn[offset] )
if( offset == even ) AX.LSB = [loc16].LSB; AX.MSB = 0x00; if( offset == odd ) AX.LSB = [loc16].MSB; AX.MSB = 0x00;
else
AX.LSB = [loc16].LSB; AX.MSB = 0x00;
</syntaxhighlight>
<syntaxhighlight lang='c'>
Instruction: MOVB loc16,AX.LSB Offset: AR0, AR1 or 3-bit value
if( loc16 == *+XARn[offset] )
if( offset == even ) [loc16].LSB = AX.LSB [loc16].MSB = untouched; if( offset == odd ) [loc16].LSB = untouched; [loc16].MSB = AX.LSB;
else
[loc16].LSB = AX.LSB; [loc16].MSB = untouched;
</syntaxhighlight>
Frequently Asked Questions[edit]
Q: The prototype for __byte is &__byte(int *array, unsigned int byte_index). Is the "&" a typo?[edit]
- A: It's not a typo, the __byte intrinsic returns a C++-style reference, even in C mode.
Q: What is the difference between __byte() and __mov_byte()[edit]
- A: The __byte() intrinsic is preferred over __mov_byte.
- __mov_byte is much older, and was implemented before the compiler could support an intrinsic that returns a reference. To maintain backward compatibility, __mov_byte was left as-is, and a new intrinsic (__byte) was added which returns the reference. There is nothing you can do with __mov_byte that you can't do with __byte.