参考资料:77F6-TI DSP BIOS Real-time Operating System v6.x User’s Guide.pdf
DSP/BIOS
一、关于DSP/BIOS
DSP/BIOS 是一个可裁剪实时内核,它提供了多线程抢占、硬件抽象、实习分析、配置工具。
实时软件组件(RTSC)为模块打包和配置提供了一个标准,RTSC包含一组工具(XDCtools)和一个实时包
二、线程模块
1、DSP/BIOS 启动顺序
1) xdctools 运行时启动顺序
CPU初始化-->用户提供的重置函数-->运行cinit()以初始化C运行环境-->运行用户提供的first functions-->运行所有模块的初始化函数-->运行pinit()-->运行用户提供的 last functions-->运行main()函数
2)main()运行结束时,BIOS_start()被调用
启动函数-->使能硬件中断-->使能软件中断-->启动计时器-->启动任务
2、线程模块
1)DSP/BIOS 提供了几种不同优先级的线程,线程类型有:(从高优先级到低优先级)
硬件中断(HWI,包括计时器函数)、软件中断(SWI ,包括时钟函数)、任务、后台线程(IDLE)
硬件中断线程:HWI 线程,也叫ISR,是DSP/BIOS应用程序中优先级最高的线程
软件中断线程:软件中断由调用SWI模块API函数产生
任务线程:DSP/BIOS提供了很多内部任务通信和同步的机制,包括信号量、事件、消息队列、邮箱。
2)模块的选择
如函数功能相对简单而且有数据共享则选择SWI,如果需求复杂则选择TASK。高优先级会抢占低优先级线程,因此只有任务(task)可以等待另一个事件,比如说可用资源。SWI比TASK更高效。
几种线程的比较:
characteristic
Hwi
Swi
Task
Idle
priority
highest
2nd highest
2nd lowest
lowest
number of priority levels
family/device-specific
up to 32. Periodic functions run at the priority of the Clock Swi.
up to 32 (including for the Idle Loop)
1
Can yield and pend
No,runs to completion except for premption
no,runs to completion except for preemption
yes
should not pend.Pending would disable all registered Idle threads.
Execution states
Inactive,ready,running
Inactive,ready,running
Ready,running,blocked,terminated
Ready,running
Thread scheduler disabled by
interrupt occurs
Swi_post(),Swi_andn();Swi_dec(),Swi_inc(),Swi_or()
Task_create()
and various
task synchronization
mechanisms
(Event,
Semaphore,
Mailbox)
main() exits and no
other thread is currently
running
Stack used
System stack
(1 per program)
System stack
(1 per program)
Task stack
(1 per task)
Task stack used by
default (see Note 1)
Context saved
when preempts
other thread
Entire context
minus saved-bycallee
registers (as
defined by the TI C
compiler) are
saved to system
Certain registers
saved to system
Entire context
saved to task stack
Not applicable
Context saved
when blocked
Not applicable
Not applicable
Saves the savedby-
callee registers
(see optimizing
compiler user’s
guide for your platform).
Not applicable
Share data with
thread via
Streams, lists,
pipes, global
variables
Streams, lists,
pipes, global
variables
Streams, lists,
pipes, gates,
mailboxes,
message queues,
global variables
Streams, lists,
pipes, global
variables
Synchronize with
thread via
Not applicable
Swi trigger
Semaphores,
events, mailboxes
Not applicable
Function hooks
Yes: register,
create, begin, end,
delete
Yes:register,
create, ready,
begin, end, delete
Yes: register,
create, ready,
switch, exit, delete
No
Dynamic creation
yes
yes
yes
no
Dynamically
change priority
See Note 1
yes
yes
no
Implicit logging
Interrupt event
Post, begin, end
Switch, yield,
ready, exit
none
Implicit statistics
none
none
none
none
Thread Type
Hook Functions
Hwi
Register, Create, Begin, End, and Delete. See Section 2.3.2.
Swi
Register, Create, Ready, Begin, End, and Delete. See Section 2.4.8.
Task
Register, Create, Ready, Switch, Exit, and Delete. See Section 2.5.4.
3、硬件中断
如果硬件中断被提交多次,中断服务程序只会执行一次,因此要让硬件中断函数尽可能的短。
1)建立硬件中断对象
Hwi_Handle hwi0;
Hwi_Params hwiParams;
Hwi_Params_init(&hwiParams);
hwiParams.arg = 5;
hwi0 = Hwi_create(id, hwiFunc, &hwiParams, &eb);
相应的静态配置硬件中断创建语句:
var Hwi = xdc.useModule('ti.sysbios.hal.Hwi');
var hwiParams = new Hwi.Params;
hwiParams.arg = 5;
Program.global.hwi0 = Hwi.create(id, '&hwiFunc', hwiParams);
2)硬件中断勾子函数
注册,创建Hwi_create(),开始,结束,删除 Hwi_delete()
typedef struct Hwi_HookSet {
Void (*registerFxn)(Int); /* Register Hook */
Void (*createFxn)(Handle, Error.Block *); /* Create Hook */
Void (*beginFxn)(Handle); /* Begin Hook */
Void (*endFxn)(Handle); /* End Hook */
Void (*deleteFxn)(Handle); /* Delete Hook */
};
注册函数:void registerFxn(Int id);
创建和删除函数:void createFxn(Hwi_Handle hwi,Eror_Block *eb);void deleteFxn(Hwi_Handle hwi)
开始和结束函数:void beginFxn(Hwi_Handle hwi); void endFxn(Hwi_handle hwi)
4、软件中断
软件中断通过DSP/BIOS API 的调用而触发,比如说Swi_post()。可以产生或提交软件中断的 API 有
Swi_andn(), Swi_dec(), Swi_inc(), Swi_or(), Swi_post();
可使用以下语句来创建一个软件中断:
Swi_Handle swi0;
Swi_Params swiParams;
Swi_Params_init(swiParams);
swi0 = Swi_create(swiFunc, &swiParams, &eb);
注意:Swi_create()只能被任务级调用而不是硬件中断或另一个软件中断。
在XDCtools 中创建一个软件中断对象:
var Swi = xdc.useModule('ti.sysbios.knl.Swi');
var swiParams = new Swi.Params();
program.global.swi0 = Swi.create(swiParams);
默认创建的软件中断优先级为16,默认系统堆栈大小为 4096 bytes,也可以这样来设置 Program.stack= yourStackSize
Swi_andn(),Swi_dec(),Swi_inc(),Swi_or()和Swi_post()都可以触发软件中断执行程序。
注意:1、软件中断一旦开始执行就必须完成,不能被阻塞
2、有硬件中断时,必须由硬件分配器唤醒调用任何能够触发软件中断的代码序列
软件中断可被高优先级的线程所抢占,然而,软件中断不能被阻塞,比如说,你不能挂起一个正在等待某事的软件中断。
使用Swi_inc()来提交一个软件中断
已阅至nps77F6-TI DSP BIOS Real-time Operating System v6.x User’s Guide ::Page 53
5、执行状态和调度
Task_Mode_RUNNING
Task_Mode_READY
Task_Mode_BLOCKED
Task_Mode_TERMINATED
Task_Mode_INACTIVE
Task_Mode_RUNNING 通过调用Task_exit()变为Task_Mode_TERMINATED
通过调用函数(例如Semaphore_pend()或Task_sleep())变为Task_Mode_BLOCKED
当其他比此任务优先级更高的任务准备执行时,变为Task_Mode_READY
当一个任务使用比较多的内存时,就需要给任务分配堆栈。Task_checkstacks()和Task_stat()用来观察堆栈的大小
Task_Stat statbuf; /* declare buffer */
Task_stat(Task_self(), &statbuf); /* call func to get status */
if (statbuf.used > (statbuf.stacksize * 9 / 10)) {
Log_printf(&trace, "Over 90% of task's stack is in use.
")
}
任务钩子函数
typedef struct Task_HookSet {
Void (*registerFxn)(Int); /* Register Hook */
Void (*createFxn)(Handle, Error.Block *); /* Create Hook */
Void (*readyFxn)(Handle); /* Ready Hook */
Void (*switchFxn)(Handle, Handle); /* Switch Hook */
Void (*exitFxn)(Handle); /* Exit Hook */
Void (*deleteFxn)(Handle); /* Delete Hook */
};
1)注册函数
注册函数在系统初始化时中断使能前被调用,void registerFxn(int id)
2)创建和删除函数
void createFxn(Task_Handle task,Error_Block *eb);
void deleteFxn(Task_Handle task)
3)开关函数
void switchFxn(Task_Handle prev,Task_Handle next);中断已使能
4)准备函数
void readyFxn(Task_Handle task),中断已使能
5)退出函数
void exitFxn(Task_Handle task),中断已使能
task hooks example:
/* ======== TaskHookExample.c ========
* This example demonstrates basic task hook processing
* operation for dynamically created tasks. */
#include
#include
#include
#include
#include
#include
#include
Task_Handle myTsk0, myTsk1, myTsk2;
Int myHookSetId, myHookSetId2;
/* HookSet functions */
/* ======== myRegister ========
* invoked during Swi module startup before main()
* for each HookSet */
Void myRegister(Int hookSetId)
{
System_printf("myRegister: assigned HookSet Id = %d
",
hookSetId);
myHookSetId = hookSetId;
}
Tasks
Threading Modules 2-51
/* ======== myCreate ========
* invoked during Task_create for dynamically
* created Tasks */
Void myCreate(Task_Handle task, Error_Block *eb)
{
String name;
Ptr pEnv;
name = Task_Handle_name(task);
pEnv = Task_getHookContext(task, myHookSetId);
System_printf("myCreate: task name = '%s', pEnv = 0x%x
",
name, pEnv);
Task_setHookContext(task, myHookSetId, (Ptr)0xdead);
}
/* ======== myReady ========
* invoked when Task is made ready to run */
Void myReady(Task_Handle task)
{
String name;
Ptr pEnv;
name = Task_Handle_name(task);
pEnv = Task_getHookContext(task, myHookSetId);
System_printf("myReady: task name = '%s', pEnv = 0x%x
",
name, pEnv);
Task_setHookContext(task, myHookSetId, (Ptr)0xc0de);
}
/* ======== mySwitch ========
* invoked whenever a Task switch occurs/is made ready to run */
Void mySwitch(Task_Handle prev, Task_Handle next)
{
String prevName;
String nextName;
Ptr pPrevEnv;
Ptr pNextEnv;
if (prev == NULL) {
System_printf("mySwitch: ignoring dummy 1st prev Task
");
}
Tasks
2-52
else {
prevName = Task_Handle_name(prev);
pPrevEnv = Task_getHookContext(prev, myHookSetId);
System_printf("mySwitch: prev name = '%s',
pPrevEnv = 0x%x
", prevName, pPrevEnv);
Task_setHookContext(prev, myHookSetId, (Ptr)0xcafec0de);
}
nextName = Task_Handle_name(next);
pNextEnv = Task_getHookContext(next, myHookSetId);
System_printf(" next name = '%s', pNextEnv = 0x%x
",
nextName, pNextEnv);
Task_setHookContext(next, myHookSetId, (Ptr)0xc001c0de);
}
/* ======== myExit ========
* invoked whenever a Task calls Task_exit() or falls through
* the bottom of its task function. */
Void myExit(Task_Handle task)
{
Task_Handle curTask = task;
String name;
Ptr pEnv;
name = Task_Handle_name(curTask);
pEnv = Task_getHookContext(curTask, myHookSetId);
System_printf("myExit: curTask name = '%s', pEnv = 0x%x
",
name, pEnv);
Task_setHookContext(curTask, myHookSetId, (Ptr)0xdeadbeef);
}
/* ======== myDelete ========
* invoked upon Task deletion */
Void myDelete(Task_Handle task)
{
String name;
Ptr pEnv;
name = Task_Handle_name(task);
pEnv = Task_getHookContext(task, myHookSetId);
System_printf("myDelete: task name = '%s', pEnv = 0x%x
",
name, pEnv);
}
Tasks
Threading Modules 2-53
/* Define 3 identical tasks */
Void myTsk0Func(UArg arg0, UArg arg1)
{
System_printf("myTsk0 Entering
");
System_printf("myTsk0 Calling Task_yield
");
Task_yield();
System_printf("myTsk0 Exiting
");
}
Void myTsk1Func(UArg arg0, UArg arg1)
{
System_printf("myTsk1 Entering
");
System_printf("myTsk1 Calling Task_yield
");
Task_yield();
System_printf("myTsk1 Exiting
");
}
Void myTsk2Func(UArg arg0, UArg arg1)
{
System_printf("myTsk2 Entering
");
System_printf("myTsk2 Calling Task_yield
");
Task_yield();
System_printf("myTsk2 Exiting
");
}
/* ======== main ======== */
Int main(Int argc, Char* argv[])
{
Task_Params params;
Task_Params_init(¶ms);
params.instance->name = "myTsk0";
myTsk0 = Task_create(myTsk0Func, ¶ms, NULL);
params.instance->name = "myTsk1";
myTsk1 = Task_create(myTsk1Func, ¶ms, NULL);
params.instance->name = "myTsk2";
myTsk2 = Task_create(myTsk2Func, ¶ms, NULL);
BIOS_start();
return (0);
}
Tasks
2-54
/* ======== myIdleFunc ======== */
Void myIdleFunc()
{
System_printf("Entering idleFunc().
");
Task_delete(&myTsk0);
Task_delete(&myTsk1);
Task_delete(&myTsk2);
System_exit(0);
}
5、分时调度P76
6、空闲循环
空闲循环是DSP/BIOS的后台线程,当没有HWI,SWI 或Task 运行的时候,它就会运行。其他任何线程都可以抢占,空闲循环具有最低的优先级
7、使用硬件中断,软件中断,任务线程的例子
P82
三、同步模块
1、信号量
信号量对象可定义为计数和信号量,被用作任务同步和互斥。信号量的值不能超过1。配置信号量的语句:config Mode mode= Mode_COUNTING
可以使用Semaphore_create()和Semaphore_delete()来创建和删除一个信号量。
Semaphore_pend()用于等待一个信号量,如果计数信号量大于0,Semaphore_pend()计数并返回,否则等待Semaphore_post()。可通过semaphore_pend()来设置超时等待。
semaphore example using three writer tasks:
/* ======== semtest.c ======== */
#include
#include
#include
#include
#include
#include
#include
#define NUMMSGS 3 /* number of messages */
#define NUMWRITERS 3 /* number of writer tasks created with */
/* Config Tool */
typedef struct MsgObj {
List_Elem elem; /* first field for List */
Int id; /* writer task id */
Char val; /* message value */
} MsgObj, *Msg;
Void reader();
Void writer();
/* The following objects are created statically. */
extern Semaphore_Handle sem;
extern List_Handle msgList;
extern List_Handle freeList;
/* ======== main ======== */
Int main(Int argc, Char* argv[])
{
Int i;
MsgObj *msg;
msg = (MsgObj *) Memory_alloc(NULL, NUMMSGS * sizeof(MsgObj),
0, NULL);
/* Put all messages on freeList */
for (i = 0; i < NUMMSGS; msg++, i++) {
List_put(freeList, (List_Elem *) msg);
}
BIOS_start();
System_exit(0);
return(0);
}
/* ======== reader ======== */
Void reader()
{
Msg msg;
Int i;
for (i = 0; i < NUMMSGS * NUMWRITERS; i++) {
/* Wait for semaphore to be posted by writer(). */
Semaphore_pend(sem, BIOS_WAIT_FOREVER);
/* get message */
msg = List_get(msgList);
/* print value */
System_printf("read '%c' from (%d).
", msg->val,
msg->id);
/* free msg */
List_put(freeList, (List_Elem *) msg);
}
System_printf("reader done.
");
}
/* ======== writer ======== */
Void writer(Int id)
{
Msg msg;
Int i;
for (i = 0; i < NUMMSGS; i++) {
/* Get msg from the free list. Since reader is higher
* priority and only blocks on sem, list is never
* empty. */
msg = List_get(freeList);
/* fill in value */
msg->id = id;
msg->val = (i & 0xf) + 'a';
System_printf("(%d) writing '%c' ...
", id, msg->val);
/* put message */
List_put(msgList, (List_Elem *) msg);
/* post semaphore */
Semaphore_post(sem);
}
System_printf("writer (%d) done.
", id);
}
result:
(0) writing 'a' ...
read 'a' from (0).
(0) writing 'b' ...
read 'b' from (0).
(0) writing 'c' ...
read 'c' from (0).
writer (0) done.
(1) writing 'a' ...
read 'a' from (1).
(1) writing 'b' ...
read 'b' from (1).
(1) writing 'c' ...
read 'c' from (1).
writer (1) done.
(2) writing 'a' ...
read 'a' from (2).
(2) writing 'b' ...
read 'b' from (2).
(2) writing 'c' ...
read 'c' from (2).
reader done.
writer (2) done.
2、事件模式
事件提供了一种线程间通信和同步的方法,它和信号量相似。
只有TASK可以调用Event_pend(),HWI,SWI以及其他TASK都能调用Event_post()。
UInt Event_pend(Event_Handle event,
UInt andMask,
UInt orMask,
UInt timeout);
Void Event_post(Event_Handle event,
UInt eventIds);
3、Gates
GateHwi,GateSwi,GateTask,GateMutex,GateMutexPri
4、邮箱
Mailbox_pend()被用来从一个邮箱中读取一个缓冲,如果邮箱是空的,则Mailbox_pend()阻塞。Mailbox_post()被用来提交一个缓冲到邮箱里。如果邮箱为空,Mailbox_post()阻塞。
四、时间服务
与计时器有关的函数
五、内存
与内存分配有关
HeapMem,HeapBuf,HeapMultiBuf
六、硬件抽象层
1、硬件抽象接口
2、HWI 模式
3、计时器模式
4、Cache 模式
5、硬件抽象层组织包
参考资料:TMS320C55x DSP BIOS 5.x Application Programming Interface (API) Reference Guide.pdf
DSP/BIOS Modules
ATM
Module:
Atomic functions written in assembly language
BUF
Module :
Maintains buffer pools of fixed size buffers
C55
Module :
Target-specific functions
CLK
Module :
System clock manager
DEV
Module
Device driver interface
GBL
Module
Global setting manager
GIO
Module
I/O module used with IOM mini-drivers
HOOK
Module
Hook function manager
HST
Module
Host channel manager
HWI
Module
Hardware interrupt manager
IDL
Module
Idle function and processing loop manager
LCK
Module
Resource lock manager
LOG
Module
Event Log manager
MBX
Module
Mailboxes manager
MEM
Module
Memory manager
MSGQ
Module
Variable-length message manager
PIP
Module
Buffered pipe manager
POOL
Module
Allocator interface module
PRD
Module
Periodic function manager
PWRM
Module
Reduce application’s power consumption
QUE
Module
Queue manager
RTDX
Module
Real-time data exchange manager
SEM
Module
Semaphores manager
SIO
Module
Stream I/O manager
STS
Module
Statistics object manager
SWI
Module
Software interrupt manager
SYS
Module
System services manager
TRC
Module
Trace manager
TSK
Module
Multitasking manager
在学习 DSP/BIOS APIs 之前先学习一下 BIOS Tconf Language
参考文档:Bios_Tconf_User_Guide.pdf、Bios_Tconf_Language_coding_Standards.pdf
使用 Tconf 脚本来配置 DSP/BIOS 中的应用程序。
一、简单认识 Tconf 脚本
以下给出怎样使用文本编辑器来建立一个 Tconf 脚本,配置了一个简单的应用程序,一个名为 “trace” 的LOG对象打印出“hello world”
#include
#include
#include "hellocfg.h"
/* ======== main ======== */
Void main()
{
LOG_printf(&trace, "Hello World!");
/* fall into DSP/BIOS idle loop */
return;
}
为应用程序编写 Tconf 脚本的步骤:
1、建立一个后缀名为 .tcf 的文本文件
2、加载一个平台 如:utils.loadPlatform("ti.platforms.dsk6416");
3、添加语句来创建对象及设置他们的属性
bios.enableRealTimeAnalysis(prog);
bios.enableRtdx(prog);
然后创建一个 “trace” 的 LOG 对象,最后设置 LOG_system 的大小
var trace;
trace = bios.LOG.create("trace");
trace.bufLen = 1024;
trace.logType = "circular";
bios.LOG_system.bufLen = 512;
4、在文件的最后写下这种语句:
if (config.hasReportedError == false) {
prog.gen();
}
以上步骤做完后,就完成了这个 hello 应用程序的脚本:
/* Load the DSK6416 platform. */
utils.loadPlatform("ti.platforms.dsk6416");
/* Enable needed DSP/BIOS features */
bios.enableRealTimeAnalysis(prog);
bios.enableRtdx(prog);
/* Create and initialize a LOG object */
var trace;
trace = bios.LOG.create("trace");
trace.bufLen = 1024;
trace.logType = "circular";
/* Set the buffer length of LOG_system buffer */
bios.LOG_system.bufLen = 512;
// !GRAPHICAL_CONFIG_TOOL_SCRIPT_INSERT_POINT!
if (config.hasReportedError == false) {
prog.gen();
}
二、运行 Tconf 脚本
1、 Tconf 脚本是通过一个多功能 tconf 命令行来运行,这个可执行 tconf 文件位于 xdctools 子文件夹下
tconf -Dconfig.importPath="C:/dspbios/bios_5_20/packages" hello.tcf
2、生成的文件
❏ cfg_c.c. Source file to define DSP/BIOS structures andproperties.
❏ cfg.h. Includes DSP/BIOS module header files anddeclares external variables for objects in the configuration file.
❏ cfg.s##. Assembly source file for DSP/BIOS settings.Since in our example we loaded dsk6416 platform, based on 64architecture, the name of this file is hel ocfg.s64.
❏ cfg.h##. Assembly language header file included byprogramcfg.s##. In our example, the name of this file is hellocfg.h64.
❏ cfg.cmd. Linker command file.
❏ .cdb. Configuration Data Base (CDB) file. Read-only file.No longer used as a source file.
多功能 tconf 命令行
1、设置环境变量 myScript = environment["config.scriptName"];
例如,如果你要在 D:/platforms 目录下新建你的自定义平台,必须设置config.importpath 的路径:tconf -Dconfig.importPath="d:/platforms" hello.tcf
2、参数数组变量,如
numOfTasksToCreate = arguments[0];
numOfReaders = arguments[1];
numOfWriters = arguments[2];
Tconf 操作模式
DSP/BIOS configuration tool
command-line mode
GUI debugger
interactive mode
三、Tconf 语言和对象模式
1、目标内容对象模型
2、加载其他脚本的方法
load()
utils.importFile()
utils.loadPlatform()
3、使能 DSP/BIOS 组件
首选的方法是通过调用 bios 命名空间来使能和禁用 DSP/BIOS 组件。如:
bios.enableRealTimeAnalysis(prog); // enables RTA
bios.enableMemoryHeaps(prog); // enables heaps
bios.enableRtdx(prog); // enables RTDX
bios.enableTskManager(prog); // enables tasks
bios.disableRealTimeAnalysis(prog); // disables RTA
bios.disableMemoryHeaps(prog); // disables heaps
bios.disableRtdx(prog); // disables RTDX
bios.disableTskManager(prog); // disables tasks
4、对象与属性的命名和引用
5、模块和实例的属性命名
6、print() 函数
for (var i in obj) {
print("obj." + i + " = " + obj[i])
}
四、Tconf 平台文件
五、Tconf 对象参考模型
config class:board(), boards(), create(), destroy(), warn()
borad class: cpus(),create(),destroy(),getMemoryMap()
cpu class:create(),destroy(),getMemoryMap(),program(),programs()
program class:extern(),externs(),destroy(),gen(),get(),module(),modules()
memory class
extern class
module class:create(),instance(),instances()
instance class:destroy(),references()
六、DSP/BIOS 配置工具(Gconf)
Tconf Language coding
模块对象:var myModule = { }
初始化函数: myModule.init = function() { }
在模块文件后,初始化函数应该被调用:myModule.init()
内部函数. 如果模块定义了一个内部函数,那这个函数必须通过 “internal” 对象进行定义,如果你需要建立一个内部函数,在建立模块对象后就立即建立内部函数对象:
var myModule.internal = {};
内部函数必须使用内部对象来定义: myModule.internal.myInternalFxn = function() {}
例如:
/*
* myModule.tci
*/
/* define the myModule object */
var myModule = {};
/* define myModule’s variables in alphabetical order */
myModule.myInteger = 1;
myModule.myString = “hello”;
/* define myModule’s functions in alphabetical order */
myModule.foo = function()
{
}
myModule.init = function()
{
}
myModule.xyz = function()
{
/*
* These variables do not need to be declared in the
* alphabetical list above because they are local to this function.
*/
var x;
var y;
var z;
x = y = z = 2;
}
/* explicitly call the init function */
myModule.init();
添加模块源文件,如:utils.importFile("dsk6713_common.tci");
Tconf 代码结构
1、Platform-independent files(存储为 .tci 文件)
2、Platform-dependent files(一般存储为 .tcf 文件)
词法约定:
标识符:
变量第一个单词小写后面为大写,如:var countNumberFrames;
关键字和;后一般跟一个空格。
函数定义:
模块函数:使用以下格式
myModule.myFunction = function (argument1, argument2)
{
var i;
for (i = 0; i < 10; i++) {/* note the blank line before this */
argument1 += argument2;
}
return (argument1);
}
非模块函数:使用以下格式
function myFunction (argument1)
{
var x;
x = argument1;
return (x);
}