A P P E N D I X  A

Tutorial

This appendix is a tutorial to tejacc programming. Topics include:


Application Code

The application used for the tutorial has two threads, tick and tock. The tick thread sends a countdown (9, 8, ..., 0) to the tock thread using a channel. Both of the threads run in a single process called ticktock.

The application code is a file called ticktock.c. The application code has a ticker function for the tick thread, and a tocker function for the tock thread. CODE EXAMPLE A-1 lists the ticktock.c file and provides comment.

 


CODE EXAMPLE A-1 ticktock.c File and Comments
#include <stdio.h> 

stdio.h and teja_late_binding.h are included. This action declares the Netra DPS late-binding API.

#include “teja_late_binding.h”
 

 

void 

The ticker function uses two late-binding objects, a memory pool called tick_memory_pool and a channel called ticktock_channel. These functions are declared in the software architecture definition. The function loops ten times, sending the count over the ticktock_channel once every second. teja_wait_time is a macro of teja_wait defined in the teja_late_binding.h file.

ticker(void) 
{  
  short i;  
  char * node = 0;  
  int ret; 
  for(i=9; i>=0; i--) {  
    teja_wait_time(1, 0); 
    node = (char *) teja_memory_pool_get_node (tick_memory_pool); 
    if (!node) { 
      printf (“Memory pool is empty!”); 
      continue; 
    } 
    sprintf(node, "%d...", i); 
    do { 
      ret = teja_channel_send(ticktock_channel, i, &node, size of (char *)); 
		if (ret < 0) {
			printf(“Failed to send %s\n”, node);
		} else {
			printf(“%s sent\n”, node);
		}
    } while (ret < 0); /* if channel full, spin & keep trying */  
  }  
}
 

 

void 

The tocker function loops forever, and in each iteration waits forever for a message to come in over the ticktock_channel. The teja_wait function is instructed to poll every tenth of a second (1E8 nanoseconds). TEJA_INFINITE_WAIT is defined in the teja_late_binding.h file.

tocker(void) 
{ 
  short i; 
  char * node = 0; 
  while(1) {
    teja_wait(TEJA_INFINITE_WAIT, 0, 0, (int) 1E8, 
      &i, (void*) &node, size of (char *), ticktock_channel, NULL); 
    if (i > 0) { 
      printf(“Received %s\n”, node); 
      teja_memory_pool_put_node (tick_memory_pool, node); 
    } else if (i == 0) { 
      printf(“BLAST OFF!!!\n”); 
      break; 
    }  
  } 
}
 

 

int 

This simple example needs no initialization. The init function is provided as an example to show how an initialization function can be mapped to a process.

init(void) 
{ 
  printf(“init\n”); 
  return 0; 
}


Configuration Code

Unlike the application code, the configuration code is target specific. The configuration code is written to a file called config.c and contains the hardware architecture, software architecture, and the mapping to the application code. CODE EXAMPLE A-2 lists the config.c file and provides comment.


CODE EXAMPLE A-2 config.c File and Comments
#include <stdio.h> 

Teja configuration APIs are declared. This example targets generic PCs and so includes teja_cmt.h from the Sun CMT chip support package. The package has a function to create the CMT1 board architecture. That function is declared as external

#include “teja_hardware_architecture.h” 
#include “teja_software_architecture.h” 
#include “teja_mapping.h” 
#include “csp/sun/teja_cmt.h” 
extern teja_architecture_t 
create_cmt1board_architecture( 
  teja_architecture_t container, const char *name);
 
 
int 

A user-defined hardware architecture called top is created as a container for the PC architecture

hwarch(void) 
{ 
  teja_architecture_t top; 
  teja_architecture_t pc; 
  teja_architecture_t cmt1_chip; 
  top = teja_architecture_create( 
          NULL, “top”, 
          TEJA_ARCHITECTURE_TYPE_USER_DEFINED); 
  pc = create_cmt1board_architecture (top, “pc”); 
  cmt1_chip = teja_lookup_architecture (pc, “cmt1_chip”); 
  teja_architecture_set_property (cmt1_chip, “bsp_dir”, BSP_DIR); 
  return 0; 
}
int 

The software architecture consists of the raw OS running on the CMT with the ticktock process running on that. The tick and tock threads are mapped respectively to strand0 and strand1 of the CMT architecture. The ticktock_channel and the tick_memory_pool have tick as the producer and tock as the consumer.

swarch(void)  
{  
  teja_os_t os;  
  teja_process_t process;  
  teja_thread_t tick, tock;  
  teja_channel_t channel;  
  teja_memory_pool_t tick_memory_pool; 
  const char* processors[3] = {"top.pc.cmt1_chip.strand0",  
       "top.pc.cmt1_chip.strand1",  
       NULL};  
  const char* srcsets[2] = {"ticktock_srcs", NULL};  
  teja_thread_t producers[2], consumers[2]; 
  os = teja_os_create(processors, "os", TEJA_OS_TYPE_RAW);  
  process = teja_process_create(os, "ticktock", srcsets);  
  tick = teja_thread_create(process, "tick_thread");  
  tock = teja_thread_create(process, "tock_thread"); 
  teja_thread_set_property(tick, TEJA_PROPERTY_THREAD_ASSIGN_TO_PROCESSOR,  
                           "top.pc.cmt1_chip.strand0");  
  teja_thread_set_property(tock, TEJA_PROPERTY_THREAD_ASSIGN_TO_PROCESSOR,  
                           "top.pc.cmt1_chip.strand1"); 
  producers[0] = tick; producers[1] = NULL;  
  consumers[0] = tock; consumers[1] = NULL; 
  channel = teja_channel_declare  
    ("ticktock_channel",  
     TEJA_GENERIC_CHANNEL_SHARED_MEMORY_OS_BASED,  
     producers,  
     consumers); 
  tick_memory_pool = teja_memory_pool_declare  
    ("tick_memory_pool",  
     TEJA_GENERIC_MEMORY_POOL_SHARED_MEMORY_OS_BASED,  
     100,  
     32,  
     producers,  
     consumers,  
     "top.pc.dram_mem"); 
  return 0;  
}
 
 
int  

The ticker function is mapped to the tick thread. The tocker function is mapped to tock_thread. The application code has no variables to be mapped. The init function is mapped to the target process.

map(void)  
{  
  teja_map_function_to_thread("ticker", "tick_thread");  
  teja_map_function_to_thread("tocker", "tock_thread"); 
  teja_map_initialization_function_to_process(
    "init", "ticktock"); 
  return 0;  
}


Build Process


procedure icon  To Create the Binary Image

1. Create the shared library config.so by compiling the config.c file and the Netra DPS-supplied cmt1_board.c chip support file.

2. Compile the ticktock.c file using tejacc to generate the application code in the code directory.

The following makefile shows how this is done.


TEJA_INSTALL_DIR=/opt/SUNWndps/tools 
BSP_DIR=/opt/SUNWndps/bsp/Niagara1 
  
all: config.so ticktock  
  
%.o:%.c  
   cc -g -c -xcode=pic13 -xarch=v9   
           -DTEJA_RAW_CMT -DBSP_DIR='$(BSP_DIR)'   
           -I$(TEJA_INSTALL_DIR)/include $< -o $@  
  
config.so: config.o cmt1_board.o  
   ld -G -o config.so config.o cmt1_board.o   
           $(TEJA_INSTALL_DIR)/bin/libtejahwarchapi.so   
           $(TEJA_INSTALL_DIR)/bin/libtejaswarchapi.so   
           $(TEJA_INSTALL_DIR)/bin/libtejamapapi.so  
  
cmt1_board.o: $(TEJA_INSTALL_DIR)/src/csp/sun/sparc64/cmt1_board.c  
   cc -g -c -xcode=pic13 -xarch=v9   
           -DTEJA_RAW_CMT -DBSP_DIR='$(BSP_DIR)'   
           -I$(TEJA_INSTALL_DIR)/include $< -o $@  
  
ticktock: ticktock.c  
$(TEJA_INSTALL_DIR)/bin/tejacc.sh   
  -Dprintf=teja_synchronized_printf   
          -I$(BSP_DIR)/include   
  -hwarch config.so,hwarch   
  -swarch config.so,swarch   
  -map config.so,map   
  -srcset ticktock_srcs ticktock.c  
  
clean:  
   rm -rf config.so *.o code

3. Run the gmake command in the code/process_name/ generated source directory to create the application binary image.


Executing the Binary Image


procedure icon  To Execute the Binary Image

single-step bullet  Copy the binary image to the tftpboot directory of the tftp server.

The CMT machine is reset, and the system is booted. See Building and Booting Reference Applications. When the application starts, the following countdown is printed to the console.


init  
tick started. 
tock started. 
9... 
8... 
7... 
6... 
5... 
4... 
3... 
2... 
1... 
SHUTDOWN. Exiting tick thread ... 
BLAST OFF!!! 
SHUTDOWN. Exiting tock thread ...