随着多线程技术的发展,原来委以重任的main()函数也逐渐的退化和冷落,现在变成了名不副实的“主函数”。在DSP/BIOS中也同样存在这样的问题,然而main()函数的作用依然不可忽略,其与DSP/BIOS的API函数的调用上存在一定的先后关系。
在DSP/BIOS应用程序中,main()函数用于实现用户的初始化操作,片内/片外外设的配置,以及势能单独的硬件中断等,然而,main()函数并不属于DSP/BIOS的任何线程类型,它仅仅是一个匆匆过客,在作完用户期望的初始化之后,也就寿终正寝了,甚至连一片云彩都不曾带走。
值得注意的一点是,应用程序在执行main函数时,并不是所有的DSP/BIOS API函数都可以调用,其间有着相应的先后关系,这是因为,main函数启动的时候,DSP/BIOS并没有完成最终的初始化,因此,main函数对于DSP/BIOS 有些API函数的调用是受限的。
这里不得不提起DSP/BIOS的启动过程(对于Bootload暂且不谈):
1、初始化DSP:复位中断向量指向c_int00地址,DSP/BIOS程序从入口点c_int00开始运行。对C6000,初试化堆栈指针(B15)和全局页指针(B14)分别指向堆栈底部与.bss段的开始,控制寄存器AMR、IER和CSR也被初始化;
2、用.cinit段中的记录来初始化.bss段;
3、调用BIOS_init初始化DSP/BIOS模块:BIOS_init执行基本的模块初始化,然后调用MOD_init宏分别初始化每个用到的模块;
4、处理.pinit表:.pinit表包含了初始化函数的指针;
5、调用应用程序main函数:在所有DSP/BIOS模块初始化之后,调用main函数。在main函数中添加了必要的初始化代码。Main函数初始化之后CPU的控制权交给DSP/BIOS。
6、调用BIOS_start启动DSP/BIOS:BIOS_start函数是由配置工具产生的,包含在XXXcfg.snn文件中(XXX与用户对工程的起名相关,nn与使用的DSP型号相关),它负责使能DSP/BIOS模块并为每个用到的模块调用MOD_startup宏使其开始工作。
在这些工作完成之后,DSP/BIOS调用IDL_loop引导程序进入DSP/BIOS空闲循环,此时硬件和软件中断可以抢先空闲循环的执行,主机也可以和目标系统之间开始数据传输。
从DSP启动的过程来看,DSP/BIOS的初始化是分为两大阶段的,一个是位于main函数前面的BIOS_init中,一个是在main函数后面的BIOS_start中。这点让人很是疑惑main函数出现的作用,究竟什么样的API函数可以在main函数中执行呢?
这点必须弄清楚main函数前后两初始化阶段的具体作用,具体的细节可以查阅相关的技术文档,但是总体来说,BIOS_init所主要完成的是MEM模块的初始化工作,而BIOS_start负责的是使能全局中断、配置和启动定时器、打开线程调度、启动DSP/BIOS线程等。因此,在main函数中,可以调用实现动态存储器分配的函数:MEM_alloc、MEM_free;以及动态创建对象的API 函数:XXX_create、XXX_delete等。对于“假设硬件中断和定时器都已经使能的API”、或者可能引起阻塞的API函数都不可以在main函数中调用,例如CLK_gethtim、CLK_getltime、HWI_enable、HWI_disable、SWI_enable、SWI_diaable、TSK_disable、TSK_enable、SEM_pend、MBX_pend等。特别需注意的是,main函数中一定不能存在无限循环,否则整个DSP/BIOS程序将瘫痪
但是对于使DSP/BIOS线程就绪的调度函数却允许在main函数中调用,例如SEM_post、SWI_post等,其实质还是在等BIOS_start进行完所有的初始化后再执行如上的调度操作。
因此可以明白一点的是,main函数穿插在BIOS的初始化过程中,为人工干预DSP/BIOS的启动提供了机会,使得BIOS的运作更具“个性化”。其间CPU的控制权从DSP/BIOS提交给用户,然后在返回给DSP/BIOS。