Using SDCC to develop Native Java functions ------------------------------------------- Prerequisites -------------- 1) Download the latest compiler sources from http://sdcc.sourceforge.net (Subversion download), build & install the compiler. 2) Download & install tini development kit. SDCC uses 'a390' assembler to generate Native libraries, it is NOT distributed with the compiler. Tested with Version 1.02d. Small Example ------------- Hello.java :- import com.dalsemi.comm.*; import com.dalsemi.system.*; public class Hello { public static native int method1(int i,int j); static void main(String args[]) { System.out.println("Hello Started"); try { System.loadLibrary("myn.tlib"); System.out.println("Load Success"); System.out.println("Native method1 returned " + method1(200,100)); } catch (Throwable t) { System.out.println(t); } } } myn.c :- long Native_method1() _JavaNative { long l = NatLib_LoadInt(0); long k = NatLib_LoadInt(1); return l-k; } Before you start compiling make sure a) 'macro' & 'a390' are in the PATH b) The files tini.inc, ds80c390.inc, tinimacro.inc & apiequ.inc are in the SAME directory as the C file. > javac -bootclasspath /tiniclasses.jar Hello.java > java -cp /tini.jar TINIConvertor -f Hello.class -o Hello.tini -d /tini.db > sdcc -mTININative myn.c Load Hello.tini & myn.tlib into the TINI board then TINI /> java Hello.tini Hello Started Load Success Native method1 returned 100 TINI /> Details you MUST know --------------------- SDCC has a completely different and incompatible parameter passing and register usage than the TINI java environment. The Native API has been implemented using the __builtin, or intrinsic function support in SDCC . Each of the Native API functions are mapped to an SDCC intrinsic function, the code generator for the intrinsic function takes care of mapping the registers and parameters to the TINI Java environment's expectations . The _JavaNative keyword is used to map the return value from a Native function to R4:R0, by default SDCC uses DPTR:b:a to return a value. Type Mapping ------------ SDCC can support types that are upto 4 bytes (32 bits). Java SDCC ---- ---- char char short short/int int long long NOT SUPPORTED double NOT SUPPORTED _bpx & _ap --------- SDCC requires a 16 bit frame pointer to access local variables (on the stack), and function parameters . In the TININative environment _bpx is mapped to R7_B3:R6_B3 (register R7:R6 in bank3). The compiler also uses AP as a temp register, for the TINI environment this is mapped to R5_B3. Limitations ----------- The TININative environment does not have a linker. Multiplication & Division of 16 & 32 bit numbers are implemented in SDCC as library functions this implies that , division & multiplication of these numbers are not supported in the TININative environment. The compiler transforms div/mul by power of 2 to shifts . For other mul/divs there are two ways around . a) Copy the library function from the library to your code . The sources can be found in sdcc/device/lib. b) Use the --use-accelerator option, with this option the compiler will generate code to use the on-chip arithmetic accelerator for 16 bit multiplication & division & modulus. NOTE The compiler will disable interrupts during this operation to prevent corruption of MA & MB registers. MUL/DIV/MOD of unsigned quantities are more efficient than signed quantities. API Mappings ------------ As mentioned earlier the Native APIs are implemented using compiler intrinsic functions, at this time only the following functions have been mapped (more will be mapped in the future). Some Native API calls return multiple values, I haven't found a good way to handle this yet, in most cases these return a HANDLE and a pointer to ABSOLUTE memory in DPTR, in such cases SDCC will return ONLY the HANDLE and ignore the POINTER value. The HANDLE can then be used with MM_Deref to obtain the POINTER value again (I hope my assumption is correct here). SDCC Prototype Native API -------------- ---------- char NatLib_LoadByte (char parmnum); NatLib_LoadPrimitive int NatLib_LoadShort(char parmnum); NatLib_LoadPrimitive long NatLib_LoadInt (char parmnum); NatLib_LoadPrimitive char *NatLib_LoadPointer (char parmnum); NatLib_LoadPointer /* in the following cases the compiler will fill in the pointer to LibraryID when required*/ /* NatLib_Get* return mutiple values return value is HANDLE , pointer is ignored */ char NatLib_InstallImmutableStateBlock(void *state_block,int handle); NatLib_InstallImmutableStateBlock char NatLib_InstallEphemeralStateBlock(void *state_block,int handle); NatLib_InstallEphemeralStateBlock void NatLib_RemoveImmutableStateBlock (); NatLib_RemoveImmutableStateBlock void NatLib_RemoveEphemeralStateBlock (); NatLib_RemoveEphemeralStateBlock int NatLib_GetImmutableStateBlock(); NatLib_GetImmutableStateBlock int NatLib_GetEphemeralStateBlock(); NatLib_GetEphemeralStateBlock int MM_XMalloc (long size); MM_XMalloc /* returns HANDLE */ int MM_Malloc (int size); MM_Malloc /* return HANDLE */ int MM_ApplicationMalloc ( int size ); MM_ApplicationMalloc /* returns HANDLE */ int MM_Free (int handle); MM_Free char *MM_Deref (int handle); MM_Deref char MM_UnrestrictedPersist(int handle); MM_UnrestrictedPersist char System_ExecJavaProcess(char *image,int handle-to-processname) System_ExecJavaProcess void System_GetRTCRegisters(char *regsavearea) System_GetRTCRegisters void System_SetRTCRegisters(char *regsavearea) System_SetRTCRegisters void System_ThreadSleep(long timeout) System_ThreadSleep void System_ThreadSleep_ExitCriticalSection(long timeout) System_ThreadSleep_ExitCriticalSection void System_ThreadResume(char threadid,char processid) System_ThreadResume void System_SaveJavaThreadState() System_SaveJavaThreadState void System_RestoreJavaThreadState() System_RestoreJavaThreadState void System_ProcessSleep(long timeout) System_ProcessSleep void System_ProcessSleep_ExitCriticalSection(long timeout) System_ProcessSleep_ExitCriticalSection void System_ProcessYield() System_ProcessYield void System_ProcessSuspend() System_ProcessSuspend void System_ProcessResume(char processid) System_ProcessResume char System_RegisterPoll((void *)(funcpointer)()) System_RegisterPoll char System_RemovePoll((void *)(funcpointer)()) System_RemovePoll char System_GetCurrentThreadId() System_GetCurrentThreadId char System_GetCurrentProcessId() System_GetCurrentProcessId Some Notes ---------- The register convention mapping causes a lot of push & pops to be generated. The source for the built in functions can be found in file src/ds390/gen.c.