C H A P T E R  3

Tutorial

This chapter is a tutorial to tejacc programming. This chapter addresses the following topics:


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. TABLE 3-1 lists the ticktock.c file and provides comment.


TABLE 3-1 ticktock.c File and Comments
#include <stdio.h>  

stdio.h and teja_late_binding.h are included, this action declares the Teja NP 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 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. TABLE 3-2 lists the config.c file and provides comment.


TABLE 3-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 and 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 Teja-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.


Execution


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 sytem 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 ...