This document lists frequently asked development development questions about the LANai3 and LANai4 processors, with answers. Copyright (C) 1995 Myricom, Inc. The LANai3/4 Developer FAQ ************************** This document lists frequently asked questions about the LANai3 and LANai4 processors, with answers. $Revision: 1.4 $ How do I build a C program? *************************** Consider a simple C program `flash.c' which flashes the LED. Such a program can be written as follows: #include main(){ while(1){LED = RTC>>18;} } This program can be compiled using the following command: > lanai3-gcc -o flash flash.c One can also compile the program into an intermediate object file `flash.o' using the following command: > lanai3-gcc -c flash.c The object file can then be linked to produce the executable `flash' using the following command: > lanai3-gcc -o flash flash.o More generally, just about anything that can be done with `gcc' can be done with `lanai3-gcc'. These features are documented at http://www.myri.com/L3/doc/gcc_toc.html . Although one can invoke `ld' and `as' directly, we, at Myricom, have always found it more convenient to let `lanai3-gcc' invoke them for us. How do I build a C++ program? ***************************** The easiest way to build C++ programs is to name the source file `FILE.C' and then compile them just like C files. There are other alternatives, which are described in the `gcc' documentation, which may be found at http://www.myri.com/L3/doc/gcc_toc.html . How do I build a pure assembly program? *************************************** Consider a simple assembly program `flash.s' which flashes the LED. Such a program can be written as follows: .global _main _main: ld [0xffffff34],%r14 nop sha %r14,-18,%r13 bt _main st %r13,[0xffffff94] The symbol `_main' marks the entry point of your program. This program can be built using the following command: > lanai3-gcc -o flash flash.s One can also compile the program into an intermediate object file `flash.o' using the following command: > lanai3-gcc -c flash.s The object file can then be linked to produce the executable `flash' using the following command: > lanai3-gcc -o flash flash.o More generally, just about anything that can be done with `gcc' can be done with `lanai3-gcc'. These features are documented at http://www.myri.com/L3/doc/gcc_toc.html . Although one can invoke `ld' and `as' directly, we, at Myricom, have always found it more convenient to let `lanai3-gcc' invoke them for us. What is a "CLOCK_VAL"? ********************** A `CLOCK_VAL' is a number used to set various adjustable parameters inside the LANai. The adjustable parameters are used to compensate for variations in the fabrication process used to make the LANai chips. What CLOCK_VAL should I use? **************************** You shouldn't need to know what clock value is needed, because the command > lload -v VERSION_NUMBER FILE and > l3clock -v VERSION_NUMBER FILE automatically sets the clock value to the recommended value. However, for those who are curious, the current recommended clock values for LANai3 chips are `0xE0000000' for the LANai3.0, `0x01400000' for the LANai3.1, and `0x11070000' for the LANai3.2. What is a "unit number"? ************************ A "unit number" is a number indicating a particular LANai board in a machine. The numbers will range from 0 to N-1 where N is the number of LANai board in the machine. The lower the slot number of the slot in which the LANai is installed, the lower the unit number. How do I run a LANai program? ***************************** LANai executables, produced by the LANai compiler `lanai3-gcc' are loaded into the lanai an run using the `lload' command. For example, the `flash' program would be loaded into a LANai3.2 board with unit number 0 using the following command: > l3clock -u 0 -v 3.2 > lload -u 0 FILE If the unit number is zero, as is the case if there is only one LANai board in your machine, then you can omit the `-u 0' option. Also, the `l3clock' command need only be run once to set the clock value; subsequent invokations of `lload' do not require `l3clock' to be invoked again. What is the LANai3 memory layout? ********************************* The anatomy of memory containing a loaded program is as follows: +-+ <- Top of memory (128K (higher for L4.X boards)) | | }- stack (grows down) ~~~ <- Floating boundary | | }- unused memory +-+ <- _L3_end_loaded_memory (a.k.a "L3_end_loaded_memory" in C source) | | }- Loaded program +-+ <- address 0 The "loaded program" consists of the following packed chunks of data, which are placed at *increasing* adresses: 1. The code from `crt0.o', which can be found in the same place as `libgcc.a'. 2. The `.text' section of your program (the code). 3. The `.data' section of your program (the initialized data). 4. The `.bss' section of your program (the uninitialized data, which is cleared). How do I move the stack? ************************ By default, each program linked by the compiler is linked with `crt0.o' and `libgcc.a'. `crt0.o' initializes the stack and calls `main()'. To move the stack, you must replace `crt0.o' and tell the compiler not to use the default version. You can replace `crt0.o' with your own version using the following code, changing the stack pointer to suite your needs: .global start start: mov 0x20000,%sp ! stack pointer at 128K mov %sp,%fp ! frame pointer add %pc,8,%rca bt _main !call _main st %rca,[--%sp] !push return address during shadow bt . ! trap in infinite loop nop You can then link this new `crt0.s' with your own program using the following commands: > lanai3-gcc -c crt0.s > lanai3-gcc -o YOUR_FILE_NAME -nostdlib crt0.o YOUR_OBJECT_FILES -lgcc `crt0.o' MUST be the first object file or library mentioned in the final linking command to cause the code in crt0.o to be placed at address 0 in the LANai, so this code will be the first code executed after a reset. The `-nostdlib' option tells the compiler not to link with the default `crt0.o' and `libgcc.a' files. The `-lgcc' option tells the compile that despite the `-nostdlib' option, we do want to link with this library, which is required to resolve the reference to `__main()' that occurs implicitly in every C program with the function `main()'. How do I reserve memory at a fixed location? ******************************************** The simplest way to reserve some memory at a fixed location is to lower the stack from the top of memory as described in the preceeding section. If you do so, the memory between the top of the stack and the top of memory will be free to be used however you desire. Care should be taken not to lower the stack so much that it intersects program memory. However, If you are attempting to store data at a fixed location to communicate with a host program, you should consider using the function `lanai_read_symbol_table(FILENAME)' from `libLanaiDevice.c', which allows you to read the symbol table from a LANai executable. You can then use `lanai_symbol_value(TABLE, NAME)' to determine the location of any symbol name. The interface is defined in `lanai_device.h' and `src/ARCH/dev/files.c'. Using symbolic addresses this way can greatly simplify code maintenance. Unless you require data alignment larger than 8 bytes, a generally superior alternative to storing data at a fixed location to share the data with a host application is to place all the data you wish to share in a data structure and then pass a pointer to the data structure to the host during initialization. This can be done, for example, by having the LANai program store a pointer to the data structure in the `SMP' register (which was chosen because it is at a known location, readable from the host, and unused during initialization), set the `HOST_SIG_BIT' of `ISR', and wait for the `HOST_SIG_BIT' to be cleared. The host would wait for the `HOST_SIG_BIT' to be set, read the pointer from `SMP' and clear the `HOST_SIG_BIT'. If this solution is used, you will probably want to clear the `EIMR' register from the host side to prevent the host from being interrupted when the `HOST_SIG_BIT' of `ISR' is set. How to I locate unuse memory in the LANai? ****************************************** The space between the symbol `_L3_end_loaded_memory' (`L3_end_loaded_memory' in C programs) and the stack is free. You may do anything you want with it as long as you leave enough space free for the stack to grow as big as needed. How do I access "special" registers? ************************************ From C, simply use the marco defined for each special register. In assembly language, you will generally use an instruction of the form "ld [0xffffff??],%r?". If you choose to define a symbol to access the special registers, care must be taken that the symbol can be resolved a assembly time. Otherwise, for fullword loads, the assembler will assume that the load should be performed using a "Special Load Store" instructions, the special register address will be out of range of this instruction, and you will get an error when linking. The "Special Load Store" is used by default because it can address the entire range of memory (excepting the special registers), and is, consequently, perfectly suited to handle fullword relocations anywhere they are really needed. How do I switch LANai contexts? ******************************* The following simple example program switches between two contexts: one that turns the LED on and another that turns the LED off: #include void user () { while (1) { LED = 1; /* Turn on LED */ while (RTC & 1<<17); /* Pause */ RESUME_USER; /* Switch to system context */ } } void main () { IMR = 0; /* Turn of interrupts */ START_USER (user, 64*1024); /* Set up user context to run user() with user stack growing down from 64K */ while (1) { LED = 0; /* Turn off LED */ while (! (RTC & 1<<17)); /* Pause */ RESUME_USER; /* Switch to user context */ } } How do I use setjmp() and longjmp() on the LANai? ************************************************* You can simply use the following header file and assembly source for setjmp/longjmp. Here is the source to `setjmp.h': #ifndef _setjmp_h_ #define _setjmp_h_ typedef struct jmp_buf { int fp; int sp; int ra; } jmp_buf[1]; int setjmp (jmp_buf env); void longjmp (jmp_buf env, int val); #endif Here is the source to `setjmp.s': .text .globl _setjmp _setjmp: ld 4[%sp],%r14 ! Load pointer to jmp_buf from argument list add %sp,0x8,%sp ! pop return addr and arguments ! Save values for longjmp return. st %fp,[%r14++] st %sp,[%r14++] st %rca,[%r14++] ! Return 0 mov %rca, %pc mov 0,%rv .globl _longjmp _longjmp: ld 4[%sp],%r14 ! Load pointer to jmp_buf from argument list ld 8[%sp],%rv ! Set return value as specified by caller ld 8[%r14],%rca ! Read return address from jmp_buf ld 4[%r14],%sp ! Read stack pointer from jmp_buf ld [%r14],%fp ! Read frame pointer from jmp_buf mov %rca,%pc ! Return (to address from setjmp) nop ! Could not fill branch shadow Concept Index ************* * Menu: * assembly, building: Assembly Building. * building assembly: Assembly Building. * building C: C Building. * building C++: C++ Building. * C: C Building. * C++, building: C++ Building. * CLOCK_VAL, recommended: CLOCK_VAL to use. * CLOCK_VAL, what is a: CLOCK_VALs. * compiling C: C Building. * compiling C++: C++ Building. * contexts, switching: Context switching.. * flashing LED <1>: C Building. * flashing LED: Assembly Building. * IMR: Context switching.. * LED, flashing <1>: C Building. * LED, flashing: Assembly Building. * longjmp: setjmp/longjmp. * memory layout: Memory Layout. * memory, locating unused: Unused Memory. * memory, reserving at a fixed loc.: Reserving Memory. * program, running a: Running Programs. * registers, accessing special: Special Registers. * RESUME_SYSTEM: Context switching.. * RESUME_USER: Context switching.. * running a program: Running Programs. * setjmp: setjmp/longjmp. * special registers, accessing: Special Registers. * stack, moving: Moving the Stack. * START_USER: Context switching.. * switching contexts: Context switching.. * unit number: Unit Numbers.