|
|
|
Symbian OS natively runs on ARM processors. It supports three form of ARM executable code, termed Application Binary Interfaces (ABIs), called ARM4, ARMI, and THUMB.
ARM4 compiles for the ARMv4 instruction set
THUMB compiles for the THUMB (16-bit) mode subset of the ARMv4T instruction set, using BX (see below)
ARMI compiles for the ARM mode subset of the ARMv4T instruction set, using BX
The BX instruction deals with changing from ARM mode into THUMB mode. The "using BX" comment indicates that the ABI in question (ARMI and THUMB) is compiled so that it is capable of interworking with code in either mode of the ARMv4T instruction set, and will switch automatically to the right mode when calling a function or returning back to the caller.
Operating system code for ROMs may be compiled with any of the ABIs. Projects built for ARMI will work with code built in any of the three ABIs, and ARMI is therefore the recommended choice for ISVs and third parties.
Code for native targets can be built from the command line, and from the CodeWarrior IDE. In either case, the Cygnus GCC toolchain installed as part of the development kit is invoked.
The remainder of this topic notes some distinctive issues when coding and running on native targets.
ARM uses a 32-bit RISC architecture with minimal extra silicon for unnecessary control purposes. This is the main reason why the chip is so cheap, and uses so little power, which in turn is why it is so popular for battery-powered consumer devices.
One consequence of this is that 32-bit quantities must be aligned to a 32-bit machine word boundary — in other words, their address must be a multiple of four. So, for instance, the following code
TInt* p; // pointer to integers
...
TInt i=*p; // get from a pointer
will only work if p is a multiple of four at the time
it is used. If p is not a multiple of four, an access violation
will result.
For normal purposes, this restriction is transparent to the programmer, because struct and class members are aligned appropriately by the compiler and heap allocator. For example, in
struct S
{
TText8 iText; // offset 0, 1 byte
TText8 iText2; // offset 1, 1 byte
TInt32 iInteger; // offset 4, 4 bytes
};
the second byte quantity is aligned at offset 1, which is ok for
bytes. But the compiler generates two pad bytes in order to align the integer
at offset 4. Therefore, sizeof(S) is 8, not 6 as might be
expected. The compiler ensures that all quantities are aligned, whether in
structs or C arrays.
You must be aware of the alignment restriction, however, if you are implementing a packed structure of some kind. For instance, the code
TText8 array[200];
for (TInt i=0; i<=196; i++)
{
TInt* p=(TInt*) array[i]; // needs a cast
TInt n=*p; // four bytes from the array makes one integer?
}
will work under WINS and will compile with gcc. But it
will generate an access violation the second time through the loop, because
p will be one greater than a multiple of four.
To bypass this problem, you should do something like
TText8 array[200];
for (TInt i=0; i<196; i++)
{
TAny* p=array[i]; // really a TAny*, so no cast needed!
TInt n;
Mem::Copy(&n, p, sizeof(TInt)); // copy byte by byte
}
In a way, C++’s type system supports the programmer here. The packed structure can only be implemented by using casting. When you do a cast, you must always think about what might be the potentially dangerous consequences. In the ARM environment, machine word alignment is a potentially dangerous consequence that you must always bear in mind. On the other hand, when you are not using casts, the compiler will do all that is necessary to ensure machine word alignment, without programmer intervention.
On emulator targets, standard timer resolution is 1/10th second.
Under ARM, it is 1/64th second. Under both platforms, an After()
timer request is effectively rounded upwards to the machine’s timer
resolution. Also, there is a minimum wait of one tick.
Therefore, animation as used for games and other special effects must be carefully controlled for each platform.
The differences in standard timer resolution do not matter so much for communications and other time-out purposes, where a coarser grain is often acceptable. On the other hand, some protocols are much more demanding, in which case a higher-resolution time service must be used.