We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
I often use MAKEWORD and MAKEDWORD macros, which are defined to construct longer types from multiple shorter ones. e.g. -
#define MAKEWORD( h, l ) \ ( ( ( WORD )( h ) << 8 ) | ( BYTE )( l ) )
which constructs a word from two bytes.
When used with constants, the calculations are all carried out at compile time and their efficiency doesn't matter. When used with data variables, code is generated the compiler's optimisation comes into play. The 8 bit shifts can be resolved to simple mov operations.
Keil does a good job optimising the MAKEWORD macro above, but does a lot less well with a similar macro to construct an unsigned long from two words or four bytes.
The following function works much better, by doing nothing! The trick is to define the word parameters so that they are passed in the same registers as a ULONG is returned, in the correct byte order. The function can the simply return, since the return value is the parameters.
This requires that the low word is passed as the first parameter, which means it is loaded to [R6|R7]. The high word is passed as the second parameter, in [R4|R5]. A ULONG is returned in [R4|R5|R6|R7], so all is as required on entry.
The line -
$reguse _make_dword ()
is important. It informs the compiler that no registers are disturbed. Without this, the calling function may generate extra code to preserve registers.
Code saved depends on too many variables to give an exact figure, but I get back around 20 bytes for a single use within a 'C' module. Your mileage may vary.
The code should also be much faster, although I haven't tested this.
A51?MAKE_DWORD segment code rseg A51?MAKE_DWORD ;/ DWORD make_dword( WORD lo, WORD hi ); ;/____________________________________________________________________________ $reguse _make_dword () public _make_dword _make_dword: ret
> With a bit of function pointer casting, it can even be > done in pure C:
... well, that depends on what you call "pure". Calling a function through a pointer casted to any other signature than its own causes undefined behaviour. I.e. you've just built a nasty surprise generator.
Calling a function through a pointer casted to any other signature than its own causes undefined behaviour.
Undefined by the C standard. Well defined by the compiler manufacturer. And the original solution of the OP already depends on the Keil C51 calling conventions.