Special Feature
The T-Engine Forum made public on January 2004 the "T-Kernel" real-time operating system that serves as the so-called nucleus of the T-Engine Project, which makes as its greatest objective the distribution of embedded middleware [1]. Because the method of obtaining and the method of building T-Kernel have been explained in "Releasing T-Kernel Source Code" in Vol. 86 of this magazine, on this occasion we will give an explanation centering on the method of creating user programs on top of T-Kernel and the methods of customizing the kernel (the addition and deletion of system calls).
First, we will explain both the method of obtaining T-Kernel and the method of building it.
The T-Kernel source code can be obtained from the T-Engine Forum's Web page (http://www.t-engine.org/). When you select "Subscription to T-Kernel," consent to the license, and fill in the required items, an e-mail that shows the download page will be sent to you. When you access the page mentioned in that e-mail, you can download the T-Kernel source code.
Let's try actually building and running the kernel from the downloaded source code. In running as is the downloaded T-Kernel, a T-Engine development kit is needed. Here, we will decide to use the GNU base development environment [2] attached to the development kit and build T-Kernel for use with SH7727 after decompressing the source code directly below the home directory.
If you are successful in decompressing, a directory called tkernel_source is created. We register this in the environment variable BD. Outside of this, we set for future keeping the environment variables of the type shown in Table 1.
|
||
|
|
|
|
|
Top of T-Kernel source code |
|
|
GNU-related tools |
|
|
Base directory of GNU-related tools used in cross development |
|
|
SH7727 compiler, etc. |
|
|
gcc-related directory |
We compile T-Kernel in the order of the libraries, and then the main body. We build the libraries by executing make in the ~/tkernel_source/lib/build/std_sh7727 directory, and we build the main body by executing make in the ~/tkernel_source/tkernel/sysmain/build/std_sh7727 directory.
When make finishes, a file called kernel-rom.mot is created above the current directory. This is the T-Kernel object file.
Next we create a RomInfo object. When we execute make above the ~/tkernel_source/config/build/std_sh7727 directory, rominfo.mot, which is the object file of RomInfo, is created.
Finally, we transmit the two objects we created, rominfo.mot and kernel-rom.mot, in this order to the Flash ROM in T-Engine. In writing into the Flash ROM, we normally use the FlashLoad (FLLO) command of T-Engine. Because there are cases where things are different, please look at the development kit's manual for details.
Basically, we create user programs in the ~/tkernel_source/kernel/usermain/ directory.
When T-Kernel finishes the initialization of the kernel, it calls up the usermain() function that is in usermain.c of the same directory. In a state in which you have downloaded and expanded T-Kernel, this usermain() function is defined in the manner of a list. The system outputs the message "Push any key to shutdown the T-Kernel" in the debug message, waits for something from an input on top of the debug console, and if there is an input, it terminates T-Kernel.
Well then, let's try building a puzzle game on top of T-Kernel. We will decide to create it with a configuration of the type in Fig. 1.
|
|
The initial task is the usermain() function that T-Kernel starts up. As in the comments in List 1, stopping at just starting up the initial task of the user program is recommended for the processing carried out with the usermain() function. For this reason, the initial task waits for the system to start up the main task and for its termination. The main task starts up the cyclic handler used for calculating time and the key/touch panel monitoring task that exists in T-Engine. The cyclic handler starts up every 100 milliseconds, and it rewrites the screen every second. The key/touch panel monitoring task is a task that waits for an input from the buttons (hereafter called keys) and touch panel installed on T-Engine and relays that to the main task. We use a message buffer for the purpose of communicating events from the key/touch panel monitoring task to the main task.
List 1 The main function usermain() of the user program (portion extracted) |
/* * Entry routine for the user application. * At this point, Initialize and start the user application. * * Entry routine is called from the initial task for Kernel, * so system call for stopping the task should not be issued * from the contents of entry routine. * We recommend that: * (1)'usermain()' only generates the user initial task. * (2)initialize and start the user application by the user * initial task. */ EXPORT INT usermain( void ) { tm_putstring("Push any key to shutdown the T-Kernel.\n"); tm_getchar(-1); return 0; } |
The initial task runs at the very low priority level of priority level 138 (the highest priority level is 1, and the lowest priority level is 140). If you start up a task with a higher priority level than this priority level, the initial task stands by as is in executable status. After this, when the initial task changes to execution status, the system escapes the usermain() function, and T-Kernel just as it is switches into termination processing. For that reason, it is necessary to make it so that the initial task does not change to execution status outside of when you are making T-Kernel terminate.
List 2 The usermain() function of the puzzle game |
/* Initial task */ IMPORT INT usermain( void ); /* User initial task main processing */ IMPORT INT main_task( INT stcd, VP exinf ); /* Main task definition */ EXPORT const T_CTSK mtask = { NULL, /* exinf */ TA_HLNG|TA_RNG0, /* tskatr */ (FP)main_task, /* task */ 3, /* itskpri */ 8*1024, /* stksz */ 0, /* sstksz */ NULL, /* stkptr */ NULL, /* uatb */ 0, /* lsid */ 0 /* resid */ }; /* itskid - initial task * mtskid - main task, main process task * ktskid - key, touch panel monitoring task */ EXPORT ID itskid. mtskid, ktskid; /* Initial task */ EXPORT INT usermainj( void ) { /* Obtain self task ID for future keeping */ itskid = tk_get_tid(); /* Create main task and start it up */ mtskid = tk_cre_tsk((T_CTSK*)&mtask); tk_sta_tsk(mtskid, 0); /* Put self to sleep after starting up the main task * Wait for being awakened when the main task terminates */ tk_slp_tsk(TMO_FEVR); /* Termination */ return -1; } |
List 2 is the usermain() function of the puzzle game. Here, after starting up the main task of the user program, we put the initial task into wait status using the tk_slp_tsk() system call. This is a measure for the purpose of preventing the initial task from changing to execution status in which the main task has moved into wait status by means of a semaphore wait, etc., while the initial task remains in executable status. When the user program terminates, the system moves to normal T-Kernel termination processing.
List 3 Main task part of the puzzle game |
/* Key, touch panel monitoring definitions */ EXPORT const T_CTSK ktask = { NULL, /* exinf */ TA_HLNG|TA_RNG0, /* tskatr */ (FP)&kbpd_task, /* task */ 4, /* itskpri */ 8*1024, /* stksz */ 0, /* sstksz */ NULL, /* stkptr */ NULL, /* uatb */ 0, /* lsid */ 0 /* resid */ }; /* itskid - initial task * mtskid - main task, main process task * ktskid - key, touch panel monitoring task */ EXPORT ID itskid, mtskid, ktskid; /* Cyclic handler */ EXPORT ID cycid; EXPORT T_CCYC ccyc = { NULL, /* exinf */ TA_HLNG, /* cycatr */ (FP)&cyclic_hdr, /* cychdr */ 100, /* cyctim */ 0 /* cycphs */ }; /* Message buffer */ EXPORT ID mbfid; EXPORT T_CMBF cmbf = { NULL, /* exinf */ TA_TPRI, /* mkfatr */ 32, /* bufsz */ 4 /* maxmsz */ }; /* Main task */ EXPORT INT main_task( INT stcd, VP exinf ) { /* --------------------------------------------------------------------- */ /* Various initialization processes */ /* Initialize keyboard, LCD */ init_kbpd(); init_screen(); /* Create input monitoring task */ ktskid = tk_cre_tsk((T_CTSK*)&ktask); tk_sta_tsk(ktskid, 0); /* Create timer handler */ cycid = tk_cre_cyc(&ccyc); /* Create message buffer */ mbfid = tk_cre_mbf(&cmbf); /* --------------------------------------------------------------------- */ /* Main game loop */ while(1) { /* Initialize */ init_game(); /* Main game process */ if(game_proc()==0) break; /* In a case where it's been cleared, raise the level and restart */ lev++; } /* --------------------------------------------------------------------- */ /* Termination */ /* Delete resources */ tk_del_cyc(cycid); tk_del_mbf(mbfid); tk_ter_tsk(ktskid); tk_del_tsk(ktskid); /* Wake up the initial task and terminate self */ tk_rel_wai(itskid); tk_exd_tsk(); /* Does not reach here */ return 0; } |
List 3 is the main task part. Here, we define the cyclic handler and the key/touch panel monitoring task, and we start up the touch panel monitoring task. We carry out the startup and suspension of the cyclic handler with the game_proc() function, which is the main body of the game.
|
|
This puzzle game was implemented using a part of the sample code attached to the T-Engine development kits. When we compile and execute this, a screen like the one in Fig. 2 appears. There are red and blue panels on the screen, and when you click a panel, the color of your panel and neighboring panels reverse. When you make them all the same color, it will be clear. The light blue square is the cursor. using the SW1 key you move this, and you can also select the panel to reverse by pressing the SW2 key.
List 4 Makefile.usermain file (extraction) |
# source files SRC += usermain.c |
The Construction Method in a Case Where You Divide the User Program into Multiple Files
Furthermore, in a case where the user program has become large and we will divide it into multiple files, we edit they file called ~/tkernel_source/kernel/usermain/Makefile.usermain. In this file, there is a variable called SRC that shows the source code of the user program that we will compile. In the file we downloaded, things are made up in the manner of List 4. In a case where we will add src1.c and src2.c to this, we rewrite and compile the SRC variable definition of the Makefile.usermain file in the manner of List 5.
List 5 Source file added definitions to Makefile.usermain file |
# source files SRC += usermain.c srcl.c src2.c |
The license for T-Kernel, T-License (refer to "T-License" on page 21 of this magazine for details), allows you to change and utilize the T-Kernel source code as long as you do not redistribute it. When you change the T-Kernel source code and rebuild the kernel with the same method as when we built T-Kernel for the first time, you can utilized a changed kernel. Here, we will explain the method of adding and deleting system calls.
An Analysis of the Method for Calling Up T-Kernel System Calls
Before we explain the method of adding and deleting system calls, let's take a look at the method of calling up system calls in T-Kernel. In T-Kernel, a system call is called up by means of an interrupt, and that method differs depending on the target system. Here, we will give an explanation on calling up system calls on the SH7727.
T-Kernel system calls are provided in function call up form in the manner of tk_cre_tsk(), tk_wai_sem(), etc. As for these functions, the libsvc library provides them, carries out interrupts inside the library, and executes the main body of the system calls. The main body of a system call is a function with "_" attached to the head in the manner of _tk_cre_tsk(), etc.
In the directory ~/tkernel_source/lib/libsvc/src/sysdepend/std_sh7727/, one file each for each system call is arranged. The file name is something in which the extension ".S" is attached to the system call name in the manner of tk_cre_tsk.S.
List 6 tk_cre_tsl.S assembler code (portion extracted) |
.globl Csym(tk_cre_tsk) .type Csym(tk_cre_tsk), @function Csym(tk_cre_tsk): mov.1 fno, r0 trapa #TRAP_SVC rts nop .balign 4 fno: .long TFN_CRE_TSK |
In concrete terms, when we take a look at tk_cre_tsk.S, it is made up in the manner of List 6. In List 6, we have set a macro defined constant called TFN_CRE_TSK in register r0, and we have turned on an interrupt by means of the trapa instruction. This trapa is an instruction that generates an exception, and by means of this, the call_entry function is called up (List 7).
|
/* Register exception handler used on OS */ define_inthdr(TRAP_SVC, call_entry); define_inthdr(TRAP_RETINT, _tk_ret_int); define_inthdr(TRAP_DISPATCH, dispatch_entry); define_inthdr(TRAP_LOADSR load_SR); |
This call_entry() function is described with an assembler in ~/tkernel_source/kernel/sysdepend/cpu/sh7727/cpu_support.S. With this function, besides carrying out register evacuation and the like for interrupts, we call up functions that use and deal with values specified in register r0 at the time of trapa execution.
The TFN_CRE_TSK constant specified in List 6 is the function code of a T-Kernel system call, and it is defined in ~/tkernel_source/include/sys/svc/tkfncd.h (List 8).
|
/* * T-Kernel function code */ #define TFN_CRE_TSK 0x80010100 #define TFN_DEL_TSK 0x80020100 #define TFN_STA_TSK 0x80030200 #define TFN_EXT_TSK 0x80040000 #define TFN_EXD_TSK 0x80050000 #define TFN_TER_TSK 0x80060100 #define TFN_DIS_DSP 0x80070000 #define TFN_ENA_DSP 0x80080000 #define TFN_CHG_PRI 0x80090200 |
This value is defined in the manner of Table 2.
|
|
|
|
|
Always 0x80 |
|
1, 2, 3, . . . are attached to the function definition order |
|
Number of function arguments |
|
Always 0x00 |
Also, together with the macro definition in List 8, a macro in the manner of List 9 is defined in ~/tkernel_source/include/sys/svc/tksvctbl.h.
|
#define _SVC_ENTRY(name) .int Csym(__##name) #define N_TFN 109 _SVC_ENTRY(tk_cre_tsk) _SVC_ENTRY(tk_del_tsk) _SVC_ENTRY(tk_sta_tsk) _SVC_ENTRY(tk_ext_tsk) _SVC_ENTRY(tk_exd_tsk) _SVC_ENTRY(tk_ter_tsk) _SVC_ENTRY(tk_dis_dsp) _SVC_ENTRY(tk_ena_dsp) _SVC_ENTRY(tk_chg_pri) |
N_TFN in List 9 is the maximum number of system calls. Because _SVC_ENTRY is a macro to which we have attached an underscore "_" to the head, when the macro is expanded, the function names of the main bodies of the system calls, such as _tk_cre_tsk(), _tk_del_tsk(), and _tk_sta_tsk(), get lined up.
This line up order matches the order of the values of the second byte inside each of the constant macros that are defined in List 8.
The call_entry() function carries out the process in which we call the function of a location that corresponds to the second byte of the numerical value at the time we do trapa. By means of this, the calling up of the system call function described in C language is finally carried out.
The Method of Adding and Deleting T-Kernel System Calls
Let's try deleting from T-Kernel the tk_ref_por system call that references a rendezvous. From the analysis of the method for calling up T-Kernel system calls that we previously saw, we understand that the following processes are necessary in order to delete system call tk_aaa_bbb from T-Kernel.
|
Delete macro constant TFN_AAA_BBB from ~/tkernel_source/include/sys/svc/tkfncd.h, and afterward revise the numerical values of the second byte of the defined macro constants so that they fall into order. |
|
Delete _SVC_ENTRY (tk_aaa_bbb) from ~/tkernel_source/include/sys/svc/tksvctbl.h, and decrease the value of the N_TFN macro constant by one. |
|
Delete the tk_aaa_bbb.S file for the purpose of issuing the trapa instruction from the libsvc subordinates. |
|
Delete the tk_aaa_bbb() prototype declaration from the ~/tkernel_source/include/tk/syscall.h. |
|
Actually delete the tk_aaa_bbb() function from among the kernel source code. |
Among these processes, the first three are not very dependent on the function contents to be added or deleted. For that reason, the script ~/tkernel_source/etc/mktksvc that automatically carries out the first three is attached to the T-Kernel source code. This script automatically generates an assembler file that issues the macro constant and trapa instruction from the system call list inside ~/tkernel_source/include/tk/syscall.h (List 10).
|
/* ---------------------------------------------------------------------- */ /* * Definition for interface library automatic generation (mktksvc) */ /*** DEFINE_TKSVC ***/ /* [BEGIN SYSCALLS */ IMPORT ID tk_cre_tsk( T_CTSK *pk_ctsk ); IMPORT ER tk_del_tsk( ID tskid ); IMPORT ER tk_sta_tsk( ID tskid, INT stacd ); . . . (omitted) . . . IMPORT ER tk_rpl_rdv( RNO rdvno, VP msg, INT rmsgsz ); IMPORT ER tk_ref_por( ID porid, T_RPOR *pk_rpor ); IMPORT ER tk_def_int( UINT dintno, T_DINT *pk_int ); . . . (omitted) . . . IMPORT ER tk_del_res( ID resid ); IMPORT ER tk_get_res( ID resid, ID ssid, VP *p_resblk ); IMPORT ER tk_set_pow( UINT powmode ); /* [END SYSCALLS] */ |
The script mktksvc regards everything between /* [BEGIN SYSCALLS] */ and /* [END SYSCALLS] */ as the prototype definitions of system calls.
Using this script, let's try deleting the the system call tk_ref_por. First, we delete the tk_ref_por prototype from the ~/tkernel_source/include/tk/syscall.h (List 11).
List 11 Deleting tk_ref_por from the system call list definition |
/* [BEGIN SYSCALLS */ IMPORT ID tk_cre_tsk( T_CTSK *pk_ctsk ); IMPORT ER tk_del_tsk( ID tskid ); IMPORT ER tk_sta_tsk( ID tskid, INT stacd ); . . . (omitted) . . . IMPORT ER tk_rpl_rdv( RNO rdvno, VP msg, INT rmsgsz ); IMPORT ER tk_def_int( UINT dintno, T_DINT *pk_int ); . . . (omitted) . . . IMPORT ER tk_del_res( ID resid ); IMPORT ER tk_get_res( ID resid, ID ssid, VP *p_resblk ); IMPORT ER tk_set_pow( UINT powmode ); /* [END SYSCALLS] */ |
In this state, we move to the ~/tkernel_source/lib/libsvc/build/std_sh7727/ libsvc build directory, where we can create a source file with make source. With make clean_source, we can delete the previous source.
As a result of make, several header files and assembler files that issue trapa instructions are created in the same numbers as the system calls. After this, we execute make install. This make install compiles the created assembler files, creates libsvc.a, and copies it into the appropriate place. However, the created header files are not automatically copied into the appropriate place. Because the created header files are placed in ~/tkernel_source/lib/libsvc/src/sysdepend/include/, please either copy all of the contents of this directory into ~/tkernel_source/include/sys/svc/, or paste a symbolic link.
Also, the system call tk_ref_por's main body _tk_ref_por() is defined in ~/tkernel_source/kernel/tkernel/src/rendezvous.c. If you delete this and rebuild the kernel, a T-Kernel without the system call tk_ref_por is created.
In a case where you delete a system call, if there is a system call that utilizes the system call that was deleted, the link will fail. It is necessary to confirm beforehand whether there is not a system call that uses the system call that you intend to delete.
In a case where you add a system call also [3], after editing of ~/tkernel_source/include/tk/syscall.h and rebuilding libsvc in the same manner, we add a system call function definition and rebuild the kernel.
____________________
[1] T-Kernel was updated to version 1.01.00 in July 2004.
[2] Here, we are using the T-Engine/SH7727 Development Kit (provided by Personal Media Corporation).
[3] As for function additions, the method of operation is not to directly add system calls, but rather to add them using extended SVC.
Makefile.usermain |
# # ---------------------------------------------------------------------- # T-Kernel # # Copyright (C) 2004 by Ken Sakamura. All rights reserved. # T-Kernel is distributed under the T-License. # ---------------------------------------------------------------------- # # Version: 1.01.00 # Released by T-Engine Forum(http://www.t-engine.org) at 2004/6/28. # # ---------------------------------------------------------------------- # # # Makefile for gmake # usermain (included from sysmain) # # source files #SRC += usermain.c SRC += puzzle.c # source file path VPATH += ../../../usermain HEADER += ../../../usermain # Manager and Driver objects I_OBJ += # additional libraries LDUSRLIBS += -lstr |
puzzle.c |
/* puzzle.c * Sample Program for T-Kernel * * Copyright (C) 2004 by T-Engine Forum and Personal Media Cooperation */ #include <basic.h> #include <tk/tkernel.h> #include <tm/tmonitor.h> #include "screen.h" /* --------------------------------------------------------------------- */ /* Routine that carries out actual initialization * As in the above instructions, initialization is carried out with a separate task * With usermain, only create that task */ IMPORT INT usermain( void ); /* Initial task */ IMPORT INT main_task( INT stcd, VP exinf ); /* User initial task main process */ IMPORT void cyclic_hdr( VP exinf); /* Cyclic handler */ IMPORT INT kbpd_task( INT stcd, VP exinf ); /* Input monitoring task */ /* Supplemental routine during the game */ IMPORT void init_game(); IMPORT W turn_panel( W bl[][], W x, W y ); IMPORT W game_proc( void ); IMPORT void draw_status( void ); IMPORT void refresh_display( void ); IMPORT void draw_panels( void ); IMPORT void draw_panel( W col, W x, W y ); IMPORT void draw_cur( W x, W y ); IMPORT void draw_text( char *str, int x, int y, int c ); IMPORT void draw_large_text( char *str, int x, int y, int d, int e, int c ); IMPORT void draw_vline( W col, W x, W y, W h ); IMPORT void draw_hline( W col, W x, W y, W w ); IMPORT void draw_fill( W x, W y, W w, W h, W col ); IMPORT W rand( void ); IMPORT ER lcdwait( W par ); IMPORT void init_screen( void ); IMPORT W read_h8( W reg, W len ); IMPORT W write_h8( W reg, W len, W dat ); IMPORT void init_kbpd( void ); IMPORT W get_pd_state( W* x, W* y ); /* --------------------------------------------------------------------- */ /* Main task definition */ EXPORT const T_CTSK mtask = { NULL, /* exinf */ TA_HLNG|TA_RNG0, /* tskatr */ (FP)&main_task, /* task */ 3, /* itskpri */ 8*1024, /* stksz */ 0, /* sstksz */ NULL, /* stkptr */ NULL, /* uatb */ 0, /* lsid */ 0 /* resid */ }; /* Keyboard, touch panel monitoring definitions */ EXPORT const T_CTSK ktask = { NULL, /* exinf */ TA_HLNG|TA_RNG0, /* tskatr */ (FP)&kbpd_task, /* task */ 4, /* itskpri */ 8*1024, /* stksz */ 0, /* sstksz */ NULL, /* stkptr */ NULL, /* uatb */ 0, /* lsid */ 0 /* resid */ }; /* itskid - initial task * mtskid - main task, main process task * ktskid - key, touch panel monitoring task */ EXPORT ID itskid, mtskid, ktskid; /* Cyclic handler */ EXPORT ID cycid; EXPORT T_CCYC ccyc = { NULL, /* exinf */ TA_HLNG, /* cycatr */ (FP)&cyclic_hdr, /* cychdr */ 100, /* cyctim */ 0 /* cycphs */ }; /* Message buffer */ EXPORT ID mbfid; EXPORT T_CMBF cmbf = { NULL, /* exinf */ TA_TPRI, /* mkfatr */ 32, /* bufsz */ 4 /* maxmsz */ }; /* --------------------------------------------------------------------- */ /* Data necessary in game */ /* Game region */ #define FIELD_WIDTH 240 #define FIELD_HEIGHT 240 /* Panel numbers */ #define PANEL_COLUMN 6 #define PANEL_ROW 6 /* Initial level */ #define FIRST_LEVEL 3 /* Number of blocks that cannot be reversed */ #define HARD_PANEL 7 W panel[PANEL_ROW][PANEL_COLUMN]; W panel_b[PANEL_ROW][PANEL_COLUMN]; W tim, step; W lev = FIRST_LEVEL; W curx = PANEL_COLUMN/2, cury = PANEL_ROW/2; /* Macro for fixing VRAM location */ #define VRAMADDR(x,y) (VRAM_ADDR_BAK+((y)*DISP_WIDTH+(x))*2) /* User initial task */ EXPORT INT usermain( void ) { /* Obtain self task ID for future keeping */ itskid = tk_get_tid(); /* Create main task and start it up */ mtskid = tk_cre_tsk((T_CTSK*)&mtask); tk_sta_tsk(mtskid, 0); /* Put self to sleep after starting up the main task * Wait for being awakened when the main task terminates */ tk_slp_tsk(TMO_FEVR); /* Termination */ return -1; } /* Main task */ EXPORT INT main_task( INT stcd, VP exinf ) { /* --------------------------------------------------------------------- */ /* Various initialization processes */ /* Initialize keyboard, LCD */ init_kbpd(); init_screen(); /* Create input monitoring task */ ktskid = tk_cre_tsk((T_CTSK*)&ktask); tk_sta_tsk(ktskid, 0); /* Create timer handler */ cycid = tk_cre_cyc(&ccyc); /* Create message buffer */ mbfid = tk_cre_mbf(&cmbf); /* --------------------------------------------------------------------- */ /* Main game loop */ while(1) { /* Initialize */ init_game(); /* Main game process */ if(game_proc()==0) break; /* In a case where it's been cleared, raise the level and restart */ lev++; } /* --------------------------------------------------------------------- */ /* Termination */ /* Delete resources */ tk_del_cyc(cycid); tk_del_mbf(mbfid); tk_ter_tsk(ktskid); tk_del_tsk(ktskid); /* Wake up the initial task and terminate self */ tk_rel_wai(itskid); tk_exd_tsk(); /* Does not reach here */ return 0; } /* Game main body */ EXPORT W game_proc( void ) { W i, x, y; W mbuf; /* Start up the cyclic handler that counts the time */ tk_sta_cyc(cycid); while(1) { /* Wait for a message */ /* Here, a four-byte message will be sent in from the input monitoring task */ tk_rcv_mbf(mbfid, &mbuf, TMO_FEVR); if (mbuf&0x80000000) { /* That on which the highest bit is standing is a key operation */ /* Up, down, left, right */ if (mbuf&1) curx = (curx+1) % PANEL_COLUMN; if (mbuf&2) curx = (curx+(PANEL_COLUMN-1)) % PANEL_COLUMN; if (mbuf&4) cury = (cury+(PANEL_ROW-1)) % PANEL_ROW; if (mbuf&8) cury = (cury+1) % PANEL_ROW; /* retry */ if (mbuf&16) { /* If it hasn't been overturned even once, reconfigure the face * When that's not the case, return to the initial state */ if (step==0) { lev--; return 1; } else { for (y=0; y<PANEL_ROW; y++) for (x=0;x<PANEL_COLUMN;x++) panel[x][y]=panel_b[x][y]; step = tim = 0; } } /* turn */ if (mbuf&0x0400) step += turn_panel(panel,curx,cury); /* exit */ if (mbuf&0x0100) return 0; } else { /* Obtain the panel of the coordinates that were touched */ x = (mbuf>>16) & 0xffff; y = mbuf & 0xffff; step += turn_panel( panel, x/(FIELD_WIDTH/PANEL_COLUMN), y/(FIELD_HEIGHT/PANEL_ROW)); } /* Has it cleared? */ i=0; for (y=0; y<PANEL_ROW; y++) for (x=0; x<PANEL_COLUMN; x++) if (panel[x][y]<=1) i += panel[x][y]; /* Clear */ if (i==0 || i==PANEL_ROW*PANEL_COLUMN-HARD_PANEL) { /* Stop the time count for the clear message display */ tk_stp_cyc(cycid); /* Clear screen display */ draw_panels(); draw_status(); draw_fill(40, 40, FIELD_WIDTH-80, FIELD_HEIGHT-80, 0x7FFF); draw_large_text("C", 56+20*0, 60+4*0, 2, 2, 0x7C00); draw_large_text("L", 56+20*1, 60+4*1, 2, 2, 0x03E0); draw_large_text("E", 56+20*2, 60+4*2, 2, 2, 0x001F); draw_large_text("A", 56+20*3, 60+4*3, 2, 2, 0x7C00); draw_large_text("R", 56+20*4, 60+4*4, 2, 2, 0x03E0); draw_large_text("!", 56+20*5, 60+4*5, 2, 2, 0x001F); draw_large_text("!", 56+20*6, 60+4*6, 2, 2, 0x7C00); draw_text("try next level!", 60, 140, 0); draw_text("- push any key -", 56, 165, 0); refresh_display(); /* If some message comes from the input monitoring task, escape the loop */ tk_rcv_mbf(mbfid,&mbuf,TMO_FEVR); break; } draw_panels(); draw_cur(curx, cury); draw_status(); refresh_display(); } /* Main loop terminates; on to next level */ return 1; } /* Cyclic handler */ EXPORT void cyclic_hdr( VP exinf ) { tim++; /* Refresh the screen display every second (=10 count) */ if (tim%10==0) { draw_status(); refresh_display(); } return; } /* Button, touch panel monitoring task */ EXPORT INT kbpd_task( INT stcd, VP exinf ) { H prek,k,i; W nk; W x, y, prebut, but; prek = k = 0; x = y = prebut = but = 0; while(1) { /* ------------------------------------------------------------------- */ /* Obtain the key status */ i = read_h8(KEYSR); if (i&2) { /* Some key or other has been pressed */ k = read_h8(KBITPR); write_h8(KEYSR,i&(~2)); /* Is there a bit that has changed from zero to one? */ nk = k&(~prek); if (nk) { /* For key operation, make the highest bit 1 */ nk |= 0x80000000; tk_snd_mbf(mbfid,&nk,4,TMO_FEVR); prek = k; } } else { write_h8(KEYSR,i&(~4)); prek = 0; } /* ------------------------------------------------------------------- */ /* Touch panel */ but = get_pd_state(&x,&y); if ((prebut==0) && (but==1)) { //x coordinate, upper two bytes; y coordinate, lower two bytes nk = ((x&0xFFFF)<<16) | (y&0xFFFF); //Make the highest bit of the touch panel zero nk &= 0x7FFFFFFF; tk_snd_mbf(mbfid,&nk,4,TMO_FEVR); } prebut = but; tk_dly_tsk(20); } tk_ext_tsk(); return 0; } /* Initialization of game information */ EXPORT void init_game() { W i,j; /* Variable initialization */ for (i=0; i<PANEL_ROW; i++) for (j=0; j<PANEL_COLUMN; j++) panel[i][j] = 0; tim = 0; step = 0; /* Assigning of blocks that cannot be reversed */ for (i=0; i<HARD_PANEL; i++) { j=rand()%(PANEL_ROW*PANEL_COLUMN); if (panel[j%PANEL_COLUMN][j/PANEL_COLUMN] != 2) panel[j%PANEL_COLUMN][j/PANEL_COLUMN]=2; else i--; } /* Randomly reverse lev spots */ for (i=0; i<lev; i++) { j=rand()%(PANEL_ROW*PANEL_COLUMN); if (panel[j%PANEL_COLUMN][j/PANEL_COLUMN]!=2) turn_panel(panel,j%PANEL_COLUMN,j/PANEL_COLUMN); else i--; } /* Save for future keeping */ for (i=0; i<PANEL_ROW; i++) for (j=0; j<PANEL_COLUMN; j++) panel_b[i][j] = panel[i][j]; /* Draw and refresh the screen */ draw_panels(); draw_status(); refresh_display(); return; } /* Reversal of blocks */ EXPORT W turn_panel( W bl[PANEL_COLUMN][PANEL_ROW], W x, W y ) { /* Check the regions once */ if (x<0 || x>=PANEL_COLUMN || y<0 || y>=PANEL_ROW) return 0; /* Reverse the thing itself */ if (bl[x][y] <= 1) bl[x][y] = 1-bl[x][y]; else return 0; /* Left */ if (x >= 1) if (bl[x-1][y] <= 1) bl[x-1][y] = 1-bl[x-1][y]; /* Right */ if (x < PANEL_COLUMN-1) if (bl[x+1][y] <= 1) bl[x+1][y] = 1-bl[x+1][y]; /* Top */ if (y >= 1) if (bl[x][y-1] <= 1) bl[x][y-1] = 1-bl[x][y-1]; /* Bottom */ if (y<PANEL_ROW-1) if (bl[x][y+1] <= 1) bl[x][y+1] = 1-bl[x][y+1]; return 1; } EXPORT void draw_panels( void ) { W i,j; /* Draw the present panels and the cursor */ for (i=0; i<PANEL_ROW; i++) for (j=0; j<PANEL_COLUMN; j++) draw_panel(panel[i][j], i, j); draw_cur(curx, cury); } EXPORT void draw_panel( W col, W x, W y) { W w,h; W tx,ty; /* Respective{middle, top left, bottom}colors */ LOCAL H colors[3][3]={ {0x7C00,0x7E10,0x4000}, {0x001F,0x0010,0x4210}, {0x2108,0x1084,0x0421} }; /* -------------- Panel drawing routine ---------------- */ /* Drawing size */ w = FIELD_WIDTH/PANEL_COLUMN; h = FIELD_HEIGHT/PANEL_ROW; x *= w; y *= h; /* Upper and left bright parts */ draw_fill(x,y,w,4,colors[col][1]); draw_fill(x,y,4,h,colors[col][1]); /* Lower and right dark spots */ for (ty=y+h-4; ty<y+h; ty++) draw_hline(x+(y+h-ty), ty, w-(y+h-ty), colors[col][2]); for (tx=x+w-4; tx<x+w; tx++) draw_vline(tx,y+(x+w-tx), h-(x+w-tx), colors[col][2]); //Things outside of those draw_fill(x+4, y+4, w-8, h-8, colors[col][0]); } EXPORT void draw_cur( W x, W y ) { W w, h, wb, hb; W col = 0x03FF; /* Draw the cursor */ /* Drawing size */ w = FIELD_WIDTH/PANEL_COLUMN; h = FIELD_HEIGHT/PANEL_ROW; x *= w; y *= h; wb = w/8; hb = h/8; /* Upper left */ draw_fill(x, y, wb*3, hb, col); draw_fill(x, y+hb, wb, hb*2, col); /* Upper right */ draw_fill(x+w-wb*3-1, y, wb*3, hb, col); draw_fill(x+w-wb-1, y+hb, wb, hb*2, col); /* Lower left */ draw_fill(x, y+h-hb-1, wb*3, hb, col); draw_fill(x, y+h-hb*3-1, wb, hb*2, col); /* Lower right */ draw_fill(x+w-wb*3-1, y+h-hb-1, wb*3, hb, col); draw_fill(x+w-wb-1, y+h-hb*3-1, wb, hb*2, col); } /* Convert num into character string str of n places * A simple version of the so-called sprintf() */ static inline void num2str( char *str, int num, int n ) { char *pnt = str; int i; int length = n; if (n <= 0) { int tnum = num; length = 1; while ((tnum /= 10)) length++; } pnt = str+length; if (num < 0) { *str = '-'; pnt++; num = -num; } *pnt = '\0'; for (i=0; i<length; i++) { *(--pnt) = '0' + num%10; num /= 10; } } EXPORT void draw_status( void ) { char str[256]; W x ,y, i, j, cnt[3]; x = 0; y = FIELD_HEIGHT; /* Initialize background with white */ draw_fill(x, y, DISP_WIDTH, DISP_HEIGHT-y, 0x7FFF); /* ---------- Drawing of the present state ------------- */ /* Counting of the number of red and blue */ cnt[0] = cnt[1] = 0; for (i=0; i<PANEL_COLUMN; i++) for (j=0;j<PANEL_ROW;j++) cnt[panel[i][j]]++; draw_text("PANEL :", x, y, 0); num2str(str, cnt[0], 2); draw_text(str, x+8*6, y, 0x7C00); num2str(str, cnt[1], 2); draw_text(str, x+8*10, y, 0x001F); x=8*15; draw_text("TIME - ", x, y, 0); num2str(str, tim/10, 0); draw_text(str, x+8*7, y, 0); x=0; y+=20; draw_text("STEP - ", x, y, 0); num2str(str, step, 0); draw_text(str, x+8*7, y, 0); x=8*15; draw_text("LEVEL - ", x, y, 0); num2str(str, lev, 0); draw_text(str, x+8*8, y, 0); x=0; y+=40; if (step) draw_text("SW2:TURN SW1:RETRY SW3:END",x,y,0); else draw_text("SW2:TURN SW1:REGEN SW3:END",x,y,0); return; } /* --------------------------------------------------------------------- */ /* Drawing vertical and horizontal lines */ EXPORT void draw_vline( W x, W y, W h, W col ) { W ty; for (ty=y; ty<y+h; ty++) out_h(VRAMADDR(x,ty),col); } EXPORT void draw_hline( W x, W y, W w, W col) { W tx; for (tx=x; tx<x+w; tx++) out_h(VRAMADDR(tx,y),col); } /* Drawing of rectangles */ EXPORT void draw_fill( W x, W y, W w, W h, W col) { W tx,ty; for (ty=y; ty<y+h; ty++) for (tx=x; tx<x+w; tx++) out_h(VRAMADDR(tx,ty),col); } EXPORT void refresh_display( void ) { W src, dst; W s; dst = VRAM_ADDR; src = VRAM_ADDR_BAK; /* Copy memory to the LCD VRAM */ for (s=DISP_HEIGHT*DISP_WIDTH*2/4; s>0; s--) { out_w(dst,in_w(src)); dst+=4; src+=4; } //Copy once again, since there are cases in which it doesn't go well for (s=32*DISP_WIDTH*2/4; s>0; s--) { out_w(dst,in_w(src)); dst+=4; src+=4; } return; } /* --------------------------------------------------------------------- */ /* Character string drawing related (from stpwtc sample) */ /* * Bit map image of a character(8x16 pixels) */ /* For example, "&" 0x00 00000000 0x38 00111000 *** 0x44 01000100 * * 0x44 01000100 * * 0x44 01000100 * * 0x44 01000100 * * 0x28 00101000 * * 0x10 → 00010000 → * 0x2a 00101010 * * * 0x4a 01001010 * * * 0x44 01000100 * * 0x84 10000100 * * 0x84 10000100 * * 0x8a 10001010 * * * 0x72 01110010 *** * 0x00 00000000 */ LOCAL UB img[94][16] = { {0x00,0x10,0x38,0x38,0x38,0x38,0x38,0x10,0x10,0x10,0x10,0x00,0x10,0x38,0x10,0x00} /* ! */ ,{0x00,0x28,0x28,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} /* " */ ,{0x00,0x00,0x28,0x28,0x2e,0x38,0xe8,0x28,0x2e,0x38,0xe8,0x28,0x28,0x28,0x00,0x00} /* # */ ,{0x10,0x10,0x38,0x54,0x92,0x92,0x50,0x30,0x18,0x14,0x92,0x92,0x54,0x38,0x10,0x10} /* $ */ ,{0x00,0x42,0xa2,0xa4,0xa4,0xa8,0x48,0x10,0x10,0x24,0x2a,0x4a,0x4a,0x8a,0x84,0x00} /* % */ ,{0x00,0x38,0x44,0x44,0x44,0x44,0x28,0x10,0x2a,0x4a,0x44,0x84,0x84,0x8a,0x72,0x00} /* & */ ,{0x00,0x20,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} /* ' */ ,{0x02,0x04,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x08,0x04,0x02} /* ( */ ,{0x80,0x40,0x20,0x20,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x20,0x20,0x40,0x80} /* ) */ ,{0x00,0x00,0x00,0x10,0x10,0x92,0x54,0x38,0x54,0x92,0x10,0x10,0x00,0x00,0x00,0x00} /* * */ ,{0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x7c,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00} /* + */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x20,0x20,0x40} /* , */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} /* - */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00} /* . */ ,{0x00,0x02,0x02,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x80,0x00} /* / */ ,{0x00,0x38,0x44,0x44,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x44,0x44,0x38,0x00} /* 0 */ ,{0x00,0x10,0x30,0x50,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00} /* 1 */ ,{0x00,0x38,0x44,0x82,0x82,0x02,0x04,0x04,0x08,0x10,0x10,0x20,0x42,0x82,0xfe,0x00} /* 2 */ ,{0x00,0x38,0x44,0x82,0x02,0x02,0x04,0x38,0x04,0x02,0x02,0x02,0x82,0x44,0x38,0x00} /* 3 */ ,{0x00,0x0c,0x0c,0x14,0x14,0x24,0x24,0x44,0x44,0x84,0x84,0xfe,0x04,0x04,0x04,0x00} /* 4 */ ,{0x00,0xfc,0x80,0x80,0x80,0x80,0xb8,0xc4,0x02,0x02,0x02,0x02,0x02,0x84,0x78,0x00} /* 5 */ ,{0x00,0x3c,0x42,0x80,0x80,0x80,0xb8,0xc4,0x82,0x82,0x82,0x82,0x82,0x44,0x38,0x00} /* 6 */ ,{0x00,0xfe,0x82,0x82,0x84,0x04,0x04,0x08,0x08,0x08,0x08,0x10,0x10,0x10,0x10,0x00} /* 7 */ ,{0x00,0x38,0x44,0x82,0x82,0x82,0x44,0x38,0x44,0x82,0x82,0x82,0x82,0x44,0x38,0x00} /* 8 */ ,{0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x46,0x3a,0x02,0x02,0x02,0x84,0x78,0x00} /* 9 */ ,{0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00} /* : */ ,{0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x30,0x30,0x10,0x10,0x20} /* ; */ ,{0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x00} /* < */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0x00} /* = */ ,{0x00,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00} /* > */ ,{0x00,0x38,0x44,0x82,0x82,0x02,0x04,0x08,0x10,0x10,0x10,0x00,0x00,0x10,0x10,0x00} /* ? */ ,{0x00,0x38,0x44,0x82,0x9a,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0x90,0x80,0x42,0x3c,0x00} /* @ */ ,{0x00,0x10,0x10,0x28,0x28,0x28,0x44,0x44,0x44,0x7c,0x82,0x82,0x82,0x82,0x82,0x00} /* A */ ,{0x00,0xf8,0x84,0x82,0x82,0x82,0x84,0xf8,0x84,0x82,0x82,0x82,0x82,0x84,0xf8,0x00} /* B */ ,{0x00,0x38,0x44,0x82,0x82,0x80,0x80,0x80,0x80,0x80,0x80,0x82,0x82,0x44,0x38,0x00} /* C */ ,{0x00,0xf8,0x84,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x84,0xf8,0x00} /* D */ ,{0x00,0xfe,0x80,0x80,0x80,0x80,0x80,0xfc,0x80,0x80,0x80,0x80,0x80,0x80,0xfe,0x00} /* E */ ,{0x00,0xfe,0x80,0x80,0x80,0x80,0x80,0xfc,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00} /* F */ ,{0x00,0x38,0x44,0x82,0x82,0x80,0x80,0x80,0x8e,0x82,0x82,0x82,0x82,0x44,0x38,0x00} /* G */ ,{0x00,0x82,0x82,0x82,0x82,0x82,0x82,0xfe,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x00} /* H */ ,{0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00} /* I */ ,{0x00,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x82,0x84,0x78,0x00} /* J */ ,{0x00,0x82,0x82,0x84,0x88,0x90,0xa0,0xd0,0x90,0x88,0x88,0x84,0x84,0x82,0x82,0x00} /* K */ ,{0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xfe,0x00} /* L */ ,{0x00,0x82,0x82,0xc6,0xc6,0xaa,0xaa,0xaa,0x92,0x92,0x92,0x82,0x82,0x82,0x82,0x00} /* M */ ,{0x00,0x82,0x82,0xc2,0xc2,0xa2,0xa2,0x92,0x92,0x8a,0x8a,0x86,0x86,0x82,0x82,0x00} /* N */ ,{0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x44,0x38,0x00} /* O */ ,{0x00,0xf8,0x84,0x82,0x82,0x82,0x82,0x84,0xf8,0x80,0x80,0x80,0x80,0x80,0x80,0x00} /* P */ ,{0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0xba,0xc6,0x44,0x3a,0x00} /* Q */ ,{0x00,0xf8,0x84,0x82,0x82,0x82,0x84,0xf8,0x88,0x88,0x84,0x84,0x84,0x82,0x82,0x00} /* R */ ,{0x00,0x38,0x44,0x82,0x82,0x80,0x40,0x30,0x0c,0x02,0x02,0x82,0x82,0x44,0x38,0x00} /* S */ ,{0x00,0xfe,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00} /* T */ ,{0x00,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x44,0x38,0x00} /* U */ ,{0x00,0x82,0x82,0x82,0x82,0x82,0x44,0x44,0x44,0x44,0x28,0x28,0x28,0x10,0x10,0x00} /* V */ ,{0x00,0x82,0x82,0x92,0x92,0x92,0x92,0xaa,0xaa,0xaa,0xaa,0x44,0x44,0x44,0x44,0x00} /* W */ ,{0x00,0x82,0x82,0x44,0x44,0x28,0x28,0x10,0x10,0x28,0x28,0x44,0x44,0x82,0x82,0x00} /* X */ ,{0x00,0x82,0x82,0x82,0x44,0x44,0x44,0x28,0x28,0x10,0x10,0x10,0x10,0x10,0x10,0x00} /* Y */ ,{0x00,0xfe,0x82,0x84,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x42,0x82,0xfe,0x00} /* Z */ ,{0x00,0x1e,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x1e,0x00} /* [ */ ,{0x00,0x82,0x82,0x44,0x44,0x28,0x28,0xfe,0x10,0x10,0xfe,0x10,0x10,0x10,0x10,0x00} /* \ */ ,{0x00,0x78,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x78,0x00} /* ] */ ,{0x18,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} /* ^ */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe} /* _ */ ,{0x30,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} /* ` */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x84,0x04,0x1c,0x64,0x84,0x84,0x8c,0x72,0x00} /* a */ ,{0x00,0x80,0x80,0x80,0x80,0x80,0xb8,0xc4,0x82,0x82,0x82,0x82,0x82,0xc4,0xb8,0x00} /* b */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x42,0x82,0x80,0x80,0x80,0x80,0x42,0x3c,0x00} /* c */ ,{0x00,0x02,0x02,0x02,0x02,0x02,0x3a,0x46,0x82,0x82,0x82,0x82,0x82,0x46,0x3a,0x00} /* d */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x82,0xfe,0x80,0x80,0x80,0x42,0x3c,0x00} /* e */ ,{0x00,0x1c,0x22,0x20,0x20,0x20,0xfc,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00} /* f */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x7a,0x84,0x84,0x78,0x40,0x80,0x7c,0x82,0x82,0x7c} /* g */ ,{0x00,0x80,0x80,0x80,0x80,0x80,0xb8,0xc4,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x00} /* h */ ,{0x00,0x10,0x10,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00} /* i */ ,{0x00,0x04,0x04,0x00,0x00,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x84,0x78} /* j */ ,{0x00,0x80,0x80,0x80,0x80,0x80,0x84,0x88,0x90,0xa0,0xe0,0x90,0x88,0x84,0x82,0x00} /* k */ ,{0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00} /* l */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x00} /* m */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0xc4,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x00} /* n */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x44,0x38,0x00} /* o */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0xc4,0x82,0x82,0x82,0x82,0xc4,0xb8,0x80,0x80} /* p */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x3a,0x46,0x82,0x82,0x82,0x82,0x46,0x3a,0x02,0x02} /* q */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x98,0xa4,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x00} /* r */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x82,0x82,0x60,0x1c,0x02,0x82,0x82,0x7c,0x00} /* s */ ,{0x00,0x00,0x20,0x20,0x20,0x20,0xfc,0x20,0x20,0x20,0x20,0x20,0x20,0x22,0x1c,0x00} /* t */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x46,0x3a,0x00} /* u */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x82,0x82,0x44,0x44,0x28,0x28,0x10,0x10,0x00} /* v */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x92,0x92,0x92,0xaa,0xaa,0xaa,0x44,0x44,0x00} /* w */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x82,0x44,0x28,0x10,0x28,0x44,0x82,0x82,0x00} /* x */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x82,0x44,0x44,0x28,0x28,0x10,0x10,0x20,0xc0} /* y */ ,{0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0xfe,0x00} /* z */ ,{0x00,0x04,0x08,0x08,0x08,0x08,0x08,0x10,0x08,0x08,0x08,0x08,0x08,0x08,0x04,0x00} /* { */ ,{0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00} /* | */ ,{0x00,0x40,0x20,0x20,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x20,0x20,0x20,0x40,0x00} /* } */ ,{0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} /* ~ */ }; /* * Drawing of the character string * Draw character string str from left corner (x,y) with color c */ EXPORT void draw_text( char *str, int x, int y, int c ) { int k, h, b, m; for (; *str != '\0'; str++) { k = *str - '!'; if (k < 0 || k >= 94) { x += 8; continue; } for (h = 0; h < 16; h++) { b = img[k][h]; for (m = 7; m >= 0; m--) { if (b & 1) out_h(VRAMADDR(x + m, y + h), c); b >>= 1; } } x += 8; } } /* * Drawing of an enlargement of the character string * Draw character s from left corner (x,y) with color c, d times width, e times height */ EXPORT void draw_large_text( char *str, int x, int y, int d, int e, int c ) { int k, h, b, m,lx,ly; for (; *str != '\0'; str++) { k = *str - '!'; if (k < 0 || k >= 94){ x+=8*d; continue; } for (h = 0; h < 16; h++) { b = img[k][h]; for (m = 7; m >= 0; m--) { if (b & 1) { for (ly=y+h*e ; ly<y+(h+1)*e; ly++) { for (lx=x+m*d ; lx<x+(m+1)*d; lx++) { out_h(VRAMADDR(lx,ly), c); } } } b >>= 1; } } x+=8*d; } } /* --------------------------------------------------------------------- */ /* Random processing */ EXPORT W rand( void ) { static W first=1,x=0; W h,m,s; /* First time initialize */ if (first==1) { first=0; /* Fittingly make a random number seed value using the SH7727 RT clock function */ h=read_h8(HRCNT ,1); m=read_h8(MINCNT,1); s=read_h8(SECCNT,1); x=(h+3)*(m+5)*(s+7); } /* Linear combination method(x=(x*A+C)%D) */ x=x*214013+253101; return (W)((x>>16)&32767); } /* --------------------------------------------------------------------- */ /* Screen related (from SH7727 screen driver) */ LOCAL ER lcdwait( W par ) { W i; /* Wait until it comes about that the LCD can be used */ for (i=0; i<5000; i++) { if ((ReadLCDC(LDPMMR) & LDPMMR_LPS) == par) return E_OK; tk_dly_tsk(10); }; return E_BUSY; } EXPORT void init_screen( void ) { W err; out_b(STBCR3, in_b(STBCR3) & ~STBCR3_MSTP11); /* Display off */ WriteLCDC(LDPMMR, LCDparm.ldpmmr); WriteLCDC(LDCNTR, 0); err = lcdwait(0); WriteLCDC(LDINTR, 0); WriteLCDC(LDICKR, LCDparm.ldickr); WriteLCDC(LDMTR, LCDparm.ldmtr); WriteLCDC(LDSMR, LDSMR_AU_16); WriteLCDC(LDDFR, LDDFR_DSPCOLOR_15C); WriteLCDC(LDLAOR, DISP_WIDTH*2); WriteLCDC(LDPALCR, 0); WriteLCDC(LDHCNR, LCDparm.ldhcnr); WriteLCDC(LDHSYNR, LCDparm.ldhsynr); WriteLCDC(LDVDLNR, LCDparm.ldvdlnr); WriteLCDC(LDVTLNR, LCDparm.ldvtlnr); WriteLCDC(LDVSYNR, LCDparm.ldvsynr); WriteLCDC(LDACLNR, LCDparm.ldaclnr); WriteLCDC(LDPSPR, LCDparm.ldpspr); WriteLCDCW(LDSARU, VRAM_ADDR); WriteLCDCW(LDSARL, 0); /* Display on */ WriteLCDC(LDCNTR, LDCNTR_DON); lcdwait(LDPMMR_LPS); return; } /* --------------------------------------------------------------------- */ /* Keys */ /* Reading and writing of H8 controller register */ EXPORT W read_h8( W reg, W len ) { W err; err = tm_extsvc(0x80,(len==2 ? reg+0x1000 : reg),0,0); return err; } EXPORT W write_h8( W reg, W len, W dat ) { W err; err = tm_extsvc(0x81,(len==2 ? reg+0x1000 : reg),dat,0); return err; } EXPORT void init_kbpd( void ) { W i; /* Make key operations possible */ i = read_h8(KEYCR); i |= 1; write_h8(KEYCR,i); /* Make it possible to utilize the touch panel */ write_h8(TPSCR, 1<<3); write_h8(TPCR, (TPCR_PEN_ONRE | TPxR_PEN_OFF | TPxR_PEN_ON | TPCR_TP_STR)); return ; } /* Initialization of the touch panel (from KB/PD driver source) */ #define ACC_DELTA (8) /* Used to prevent pen shaking */ EXPORT W get_pd_state( W *x, W *y ) { static W p_x, p_y, p_but=-1, adx, ady;/* Pen status on previous occasion */ W sts, xpos, ypos; sts=read_h8(TPSR); xpos=read_h8(XPAR); ypos=read_h8(YPAR); write_h8(TPSR, 0); if (sts < 0 || xpos < 0 || ypos < 0) return -1; if (sts & TPxR_PEN_OFF) { if (p_but == 0) goto fin; xpos = p_x; ypos = p_y; } else if (sts & TPxR_PEN_ON) { if (p_but != 0) { /* Preventing shaking of the pointer */ adx += xpos - p_x; ady += ypos - p_y; if (adx > -ACC_DELTA && adx < ACC_DELTA && ady > -ACC_DELTA && ady < ACC_DELTA) goto fin; } } else{ return 0; } adx = ady = 0; p_but = (sts & TPxR_PEN_ON) ? 1 : 0; p_x = xpos; p_y = ypos; /* Normalizing X/Y coordinates */ xpos = (xpos - TabPar.x_bias) * PDIN_XMAX / TabPar.x_span; xpos = (xpos < 0) ? 0 : ((xpos > PDIN_XMAX) ? PDIN_XMAX : xpos); ypos = (ypos - TabPar.y_bias) * PDIN_YMAX / TabPar.y_span; ypos = (ypos < 0) ? 0 : ((ypos > PDIN_YMAX) ? PDIN_YMAX : ypos); *x = xpos*DISP_WIDTH/PDIN_XMAX; *y = ypos*DISP_HEIGHT/PDIN_YMAX; fin: return p_but; } |
screen.h |
/* screen.h * Header file of Sample Program (puzzle) for T-Kernel * * Copyright (C) 2004 by T-Engine Forum and Personal Media Cooperation */ /* Display */ #define DISP_WIDTH 240 #define DISP_HEIGHT 320 #define VRAM_SIZE (DISP_WIDTH*DISP_HEIGHT*2) #define VRAM_ADDR 0x0C800000 #define VRAM_ADDR_BAK 0x0CA00000 /* LCD sample of the development environment below * obtained from (${BD}/te/driver/screen/src/sh7727/sh3lcdc.c) */ #define SH3LCDC_PALETTE 0xa4000800 /* Palette register */ #define SH3LCDC_BASE 0xa4000c00 /* LCDC */ #define STBCR3 0xa4000230 /* Standby controller register */ #define STBCR3_MSTP11 0x02 #define LDICKR 0x00 #define LDMTR 0x02 #define LDDFR 0x04 #define LDSMR 0x06 #define LDSARU 0x08 /* 32bit */ #define LDSARL 0x0c /* 32bit */ #define LDLAOR 0x10 #define LDPALCR 0x12 #define LDHCNR 0x14 #define LDHSYNR 0x16 #define LDVDLNR 0x18 #define LDVTLNR 0x1a #define LDVSYNR 0x1c #define LDACLNR 0x1e #define LDINTR 0x20 #define LDPMMR 0x24 #define LDPSPR 0x26 #define LDCNTR 0x28 /* LDICKR */ #define LDICKR_ICKSEL_CKIO 0x0000 /* Clock source: CKIO */ #define LDICKR_ICKSEL_PCLK 0x1000 /* Clock source: Pclk */ #define LDICKR_ICKSEL_LCLK 0x2000 /* Clock source: Lclk */ #define LDICKR_DCDR_1_1 0x0001 /* 1/1 */ #define LDICKR_DCDR_1_2 0x0002 /* 1/2 */ #define LDICKR_DCDR_1_4 0x0004 /* 1/4 */ #define LDICKR_DCDR_1_8 0x0008 /* 1/8 */ #define LDICKR_DCDR_1_16 0x0010 /* 1/16 */ /* LDMTR */ #define LDMTR_FLMPOL 0x8000 /* 1: FLM pulse is low active */ #define LDMTR_CL1POL 0x4000 /* 1: CL1 pulse is low active */ #define LDMTR_DISPPOL 0x2000 /* 1: DISP is low active */ #define LDMTR_DPOL 0x1000 /* 1: LCDD is low active */ #define LDMTR_MCNT 0x0400 /* 1: No MCNT signal */ #define LDMTR_CL1CNT 0x0200 /* 1: No CL1 signal */ #define LDMTR_CL2CNT 0x0100 /* 1: No CL2 signal */ #define LDMTR_MIFTYP_STN4M 0x0000 /* STN monochrome 4bit bus */ #define LDMTR_MIFTYP_STN8M 0x0001 /* STN monochrome 8bit bus */ #define LDMTR_MIFTYP_STN4C 0x0008 /* STN color 4bit bus */ #define LDMTR_MIFTYP_STN8C 0x0009 /* STN color 8bit bus */ #define LDMTR_MIFTYP_STN12C 0x000a /* STN color 12bit bus */ #define LDMTR_MIFTYP_STN16C 0x000b /* STN color 16bit bus */ #define LDMTR_MIFTYP_DSTN8M 0x0011 /* DSTN monochrome 8bit bus */ #define LDMTR_MIFTYP_DSTN16M 0x0013 /* DSTN monochrome 16bit bus */ #define LDMTR_MIFTYP_DSTN8C 0x0019 /* DSTN color 8bit bus */ #define LDMTR_MIFTYP_DSTN12C 0x001a /* DSTN color 12bit bus */ #define LDMTR_MIFTYP_DSTN16C 0x001b /* DSTN color 16bit bus */ #define LDMTR_MIFTYP_TFT16C 0x002b /* TFT color 16bit bus */ /* LDDFR */ #define LDDFR_PABD 0x0100 /* Byte data is little endian */ #define LDDFR_DSPCOLOR_1M 0x0000 /* monochrome 1bpp */ #define LDDFR_DSPCOLOR_2M 0x0001 /* monochrome 2bpp */ #define LDDFR_DSPCOLOR_4M 0x0002 /* monochrome 4bpp */ #define LDDFR_DSPCOLOR_6M 0x0004 /* monochrome 6bpp */ #define LDDFR_DSPCOLOR_4C 0x000a /* color 4bpp */ #define LDDFR_DSPCOLOR_8C 0x000c /* color 8bpp */ #define LDDFR_DSPCOLOR_15C 0x001d /* color 15bpp (5-5-5) */ #define LDDFR_DSPCOLOR_16C 0x002d /* color 16bpp (5-6-5) */ /* LDSMR */ #define LDSMR_ROT 0x2000 /* 1: rotate enable */ #define LDSMR_AU_4 0x0000 /* 4burst */ #define LDSMR_AU_8 0x0100 /* 8burst */ #define LDSMR_AU_16 0x0200 /* 16burst */ #define LDSMR_AU_32 0x0300 /* 32burst */ /* LDPALCR */ #define LDPALCR_PALS 0x0010 /* 1: CPU uses palette (read only) */ #define LDPALCR_PALEN 0x0001 /* 1: CPU uses palette */ /* LDINTR */ #define LDINTR_VINTSEL 0x1000 /* 1: Interrupt at LCD Vsync */ #define LDINTR_VINTE 0x0100 /* 1: LCDC Vsync interrupt enable */ #define LDINTR_VINTS 0x0001 /* 1: Vsync interrupt status */ /* LDPMMR */ #define LDPMMR_VCPE 0x0040 /* 1: VCPWC control enable */ #define LDPMMR_VEPE 0x0020 /* 1: VEPWC control enable */ #define LDPMMR_DONE 0x0010 /* 1: DON control enable */ #define LDPMMR_LPS 0x0003 /* 3: LCD power is ON (read only) */ /* LDCNTR */ #define LDCNTR_DON 0x0011 /* 1: LCDC enable, display on */ /* Output to palette */ #define WritePAL(adr, dat) out_w(SH3LCDC_PALETTE + (adr) * 4, (dat)) /* Input/output to LCDC */ #define WriteLCDC(adr, dat) out_h(SH3LCDC_BASE + (adr), (dat)) #define WriteLCDCW(adr, dat) out_w(SH3LCDC_BASE + (adr), (dat)) #define ReadLCDC(adr) in_h(SH3LCDC_BASE + (adr)) typedef struct { UH ldickr; UH ldmtr; UH ldhcnr; UH ldhsynr; UH ldvdlnr; UH ldvtlnr; UH ldvsynr; UH ldpmmr; UH ldaclnr; UH ldpspr; } LCDdefs; LOCAL const LCDdefs LCDparm = { 0x0108, // LDICKR 0xc02b, // LDMTR TFT 16bit data Bus 0x1d23, // LDHCNR 0x0020, // LDHSYNR 0x013f, // LDVDLNR 0x014b, // LDVTLNR 0x1140, // LDVSYNR 0xff70, // LDPMMR 0x000c, // LDACLNR 0x0500, // LDPSPR }; /* * Keyboard/pointing device controller register definition */ /* Touch panel */ #define TPCR 0x20, 1 /* Touch panel controller register */ #define TPSR 0x21, 1 /* Touch panel status register */ #define TPSCR 0x22, 1 /* Sampling controller register */ #define XPAR 0x24, 2 /* X location A/D register */ #define YPAR 0x26, 2 /* Y location A/D register */ #define DXDR 0x44, 2 /* DX dot register */ #define DYDR 0x46, 2 /* DY dot register */ #define TPCR_PEN_ONRE 0x08 #define TPxR_PEN_OFF 0x04 #define TPxR_PEN_ON 0x02 #define TPCR_TP_STR 0x01 /* Key operations register */ #define KEYCR 0x0060,1 #define KBITPR 0x0064,2 #define KEYSR 0x0062,1 /* Status (common to RTC, touch panel, keyboard, power supply controller) */ #define RTKISR 0x90, 1 #define RTKISR_IRRIF 0x10 #define RTKISR_POWERIF 0x08 #define RTKISR_KEYIF 0x04 #define RTKISR_TPIF 0x02 #define RTKISR_RTCIF 0x01 /* Various types of interrupt settings used */ #define KB_INTMASK (KEYxR_PONSW | KEYxR_KEY_OFF | KEYxR_KEY_ON) #define PD_INTMASK (TPxR_PEN_ON | TPxR_PEN_OFF) #define RTKISR_INTMASK (RTKISR_TPIF | RTKISR_KEYIF) /* * Tablet parameters (coordinate normalization parameters, and so on) */ typedef struct { W x_bias; W x_span; W y_bias; W y_span; W nodsp; W rate; } TABPAR; LOCAL TABPAR TabPar = {0xec0, -3432, 0xea0, -3360, 0, 80}; #define PDIN_XMAX 4096 #define PDIN_YMAX 3072 /* Real-time clock function */ #define SECCNT 2 #define MINCNT 3 #define HRCNT 4 |
The above article on T-Engine appeared on pages 23-29 in Vol. 89 of TRONWARE . It was translated and loaded onto this Web page with the permission of Personal Media Corporation.
Copyright © 2004 Personal Media Corporation
Copyright © 2004 Sakamura Laboratory, University Museum, University of Tokyo