Third parties should build programs for native targets (real machines running ARM processors, rather than the Emulator) using the ARMI build target. This is always done on the command line, for example:
> abld build armi urel
The form of executable code is termed an Application Binary Interface (ABI), of which ARMI is one. Operating system code in ROM may have been compiled with alternative ABIs, called ARM4 and THUMB. Projects built for ARMI will work however with code built in any of the three ABIs.
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.
Under WINS, 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.