threadx学习笔记.docx
《threadx学习笔记.docx》由会员分享,可在线阅读,更多相关《threadx学习笔记.docx(40页珍藏版)》请在冰豆网上搜索。
threadx学习笔记
threadx学习笔记
(一)
tx_ill.s文件用来处理初始化过程中的汇编语言,它是面向处理器和开发工具的。
Void_tx_initialize_low_level{
1、CPSCR|=FIQ_MODE,SETSP_fiq;
2、CPSCR|=IRQ_MODE,SETSP_irp;
3、CPSCR|=SVC_MODE,SETSP_svc;
4、设置中断向量表IRQ_TABLE;
5、设置内部TIMER线程的堆栈起始地址,堆栈大小和优先级:
:
tx_timer_stack_start,_tx_timer_stack_size,_tx_timer_priorit;
6、设置初始化后未使用内存地址的初始值_tx_initialize_unused_memory;
}
Tx_tcs.s负责在中断发生时对上次的运行现场进行保存,它保存中断上下文,为了不覆盖R14_irq离得中断返回地址,TCS的返回是通过跳到__tx_irq_processing_return地址做到的。
Tx_TCR.S负责中断处理程序执行完后的处理。
Void_tx_thread_context_save{
1、把表示中断嵌套个数的变量_tx_thread_system_state++;
2、if_tx_thread_system_state>1,PUSHR0-R3,CPSR,R14inIRQstack,B__tx_irq_processing_return;
3、elseif_tx_thread_current_ptr=0判断是否有线程正在运行,ifnot,B_tx_irq_processing_return;
4、else,PUSHContext_irqinthread’sstack,SP_thread=newSP,B_tx_irq_processing_return;
}
由于R13和R14在不同的CPU模式下对应的是不同的物理寄存器,所以若要得到中断前的线程堆栈指针,需要先返回到该线程的运行模式,同时禁止中断,取值后再返回到终端模式。
R14_irq保存的是终端发生时PC值+8,R14_svc保存得失中断前线程自己的返回地址。
所以在中段上下文中,(R14_irq-4)应该存在中断地址,而R14_svc存在R14的位置。
Void_tx_thread_context_restore{
1、_tx_thread_system_state--,if_tx_thread_system_state>0,POPR0-R3,CPSR,R14fromIRQstack,BXR14;
2、elseif_tx_thread_current_ptr=0?
if=0CPSR|=VC_MODE,CPSR|=TX_INT_ENABLE,跳到线程调度程序B_tx_thread_schedule;
3、if!
=0,则判断线程抢占是否禁止if_tx_thread_preempt_disable=0?
if!
=0,POPContext_irqfromthread’sstack,BXR14;
4、if=0,_tx_timer_time_slice=newvalue,_tx_thread_current_ptr=0,CPSR|=SVC_MODE,设置堆栈指针为系统指针SP=SP_svc,CPSR|=TX_INT_ENABLE;
5、B_tx_thread_schedule;
}
Tx_tsr.s用于从线程退回到系统态,负责保存线程的最小语境并退回到Threadx的调度循环状态。
它保存的上下文是请求上下文。
Void_tx_thread_system_return{
1、?
?
?
?
?
?
?
?
?
?
?
?
PUSHContext_request:
inthread’sstack,CPSR|=TX_INT_DISABLE;
2、?
?
?
?
?
?
?
?
?
?
?
?
_tx_thread_current_ptr->SP=SP,CPSR|=SVC_MODE;
3、?
?
?
?
?
?
?
?
?
?
?
?
设置堆栈指针为系统指针SP=SP_svc,_tx_thread_current_ptr=0,CPSR|=TX_INT_ENABLE;
4、?
?
?
?
?
?
?
?
?
?
?
?
B_tx_thread_schedule;
}
由于用户模式不能直接更改CPSR来关断的,所以要通过SWI指令进入特权模式,而且特权模式和用户模式的SP对应不同的物理寄存器,所以要在转入系统模式取得用户模式下SP,最后再回到特权模式。
TX_TS.S负责调度和恢复就绪的优先级最高的线程的最后语境。
Void_tx_thread_schedule{
1、?
?
?
?
?
?
?
?
?
?
?
?
while(_tx_thread_execute_ptr=0);
2、?
?
?
?
?
?
?
?
?
?
?
?
CPSR|=TX_INT_DISABLE,_tx_threadx_current_ptr=_tx_thread_execute_ptr;
3、?
?
?
?
?
?
?
?
?
?
?
?
_tx_thread_current_ptr->TX_run_count++,_tx_timer_time_slice=_tx_thread_current_ptr->tx_time_slice;
4、?
?
?
?
?
?
?
?
?
?
?
?
If线程堆栈的中断类型=1,restoreContext_irq,elserestoreContext_request;
}
Tx_tic.s用于开中断和关中断。
Unint_tx_thread_interrupt_control(unintnew_posture){
1、?
?
?
?
?
?
?
?
?
?
?
?
R1=CPSR;
2、?
?
?
?
?
?
?
?
?
?
?
?
SWI;
3、?
?
?
?
?
?
?
?
?
?
?
?
CPSR|=RO=newposture;
4、?
?
?
?
?
?
?
?
?
?
?
?
R0=R1,R0为返回值;
}
移植该函数时,针对不同的处理器,应盖根据准热爱寄存器CPSR的中断禁止未来设置开关中断向量,主要修改TX_PORT.H中的TX_INT_ENABLE和TX_INT_DISABLE.R0用来传递的参数和结果。
Tx_tsb.s负责创建每个线程的初始堆栈结构,这个初始的结构在线程创建时会引起中断上下文返回到_tx_thread_shell_entry函数的开头。
然后这个函数调用指定线程入口函数。
其中断类型设置为1,表示中断上下文。
Void_tx_thread_stack_build(TXTHREAD*thread_ptr,void(*function)(void)){
1、?
?
?
?
?
?
?
?
?
?
?
?
保证堆栈起始地址八字节对齐;
2、?
?
?
?
?
?
?
?
?
?
?
?
中断地址存入线程调用的入口地址PUSHfunction_ptr;
3、?
?
?
?
?
?
?
?
?
?
?
?
R0-R12,R14的初始值都设置为0,PUSH初始值;
4、?
?
?
?
?
?
?
?
?
?
?
?
要存入堆栈的CPSR值设置为用户模式,开中断,标志位清零,R1=USER_MODE,PUSHR1;
5、?
?
?
?
?
?
?
?
?
?
?
?
Thread_ptr->sp=newSP;
}
当处理一个低级的中断时,tx_tpc.s决定是否发生抢占,它是可选的,大多数端口都用不到。
TX_TIMIN.S负责处理定时中断。
这两个函数只要将它们翻译成相应ARM汇编语言就可以了。
threadx学习笔记
(二)-1
tx_kernel_enter();进入threadx核
tx_kernel_enter()
voidtx_kernel_enter(void)
所属文件?
?
?
?
调用者?
?
?
?
开关量
demo.C?
?
?
?
启动代码?
?
?
?
无
操作系统首先从从量表直接进入该函数,在函数以前没有进行任何的硬件及软件的初始化!
该函数主要包含_tx_initialize_low_level(),_tx_initialize_high_level(),tx_application_define(_tx_initialize_unused_memory),_tx_thread_schedule()。
VOID_tx_initialize_kernel_enter(VOID)
{
?
?
?
?
/*确定编译器是否已经初始化过*/
?
?
?
?
if(_tx_thread_system_state!
=TX_INITIALIZE_ALMOST_DONE)
?
?
?
?
{
?
?
?
?
?
?
?
?
/*没有初始化的话执行下面程序*/
/*设置系统状态变量来表示现正在处理过程中注意该变量在后边的中断嵌套中会使用?
?
?
?
*/
?
?
?
?
?
?
?
?
_tx_thread_system_state=TX_INITIALIZE_IN_PROGRESS;
?
?
?
?
?
?
?
?
/*进行一些基本硬件设置,启动程序等*/
?
?
?
?
?
?
?
?
_tx_initialize_low_level();
?
?
?
?
?
?
?
?
?
?
?
?
/*进行一些高级的初始化*/
?
?
?
?
?
?
?
?
_tx_initialize_high_level();
?
?
?
?
}
/*设置系统状态变量来表示现正在处理过程中注意该变量在后边的中断嵌套中会使用*/
?
?
?
?
_tx_thread_system_state=TX_INITIALIZE_IN_PROGRESS;
?
?
?
?
/*调用初始化中提供的应用程序把第一个未使用的变量地址传送给它*/
?
?
?
?
tx_application_define(_tx_initialize_unused_memory);
?
?
?
?
/*设置系统壮伟进入线程调度做准备*/
?
?
?
?
_tx_thread_system_state=TX_INITIALIZE_IS_FINISHED;
?
?
?
?
/*进入线程循环开始执行线程*/
?
?
?
?
_tx_thread_schedule();
}
_tx_initialize_low_level()
voidtx_kernel_enter(void)
所属文件?
?
?
?
调用者?
?
?
?
开关量
tx_till.s?
?
?
?
启动代码?
?
?
?
无
该函数实现对FIQ、IRQ和SVC模式下的sp寄存器的初始化,并对定时堆栈的基地址、大小和定时优先级变量进行初始化。
/*进行一些基本硬件设置,启动程序等*/
/*该函数在文件tx_ill.s文件中*/
?
?
?
_tx_initialize_low_level();
;/*VOID_tx_initialize_low_level(VOID)
;{
?
?
?
?
EXPORT_tx_initialize_low_level
_tx_initialize_low_level
;/*保存系统堆栈指针.*/
;/*_tx_thread_system_stack_ptr=(VOID_PTR)A7(SP);*/
;?
?
?
?
/*设置各个模式下的sp(堆栈指针)*/
;/*WemustbeinSVCmodeatthispoint!
*/
;
?
?
?
?
LDRa2,=|Image$$ZI$$Limit|;Getendofnon-initializedRAMarea
?
?
?
?
LDRa3,[pc,#FIQ_STACK_SIZE-.-8];获得FIO堆栈地址(这里没有弄明白,有待?
)
?
?
?
?
MOVa1,#FIQ_MODE;设置FIQ_MODE
?
?
?
?
MSRCPSR_c,a1;进入FIQ模式
?
?
?
?
ADDa2,a2,a3;计算FIQ堆栈的开始
?
?
?
?
BICa2,a2,#3;将a2的低两位清零确保堆栈的的开始为long对齐
?
?
?
?
SUBa2,a2,#4;往回退一个字
?
?
?
?
MOVsp,a2;建立FIQ堆栈指针(即FIQ模式的sp)
?
?
?
?
MOVsl,#0;Clearsl(R10)
?
?
?
?
MOVfp,#0;Clearfp(R11)
?
?
?
?
LDRa3,[pc,#SYS_STACK_SIZE-.-8]?
?
?
?
;获得IRQ(systemstacksize)
?
?
?
?
MOVa1,#IRQ_MODE;建立IRQ模式的CPSR
?
?
?
?
MSRCPSR_c,a1;进入IRQ模式
?
?
?
?
ADDa2,a2,a3;计算IRQstack的开始
?
?
?
?
?
BICa2,a2,#3;将a2的低两位清零确保堆栈的的开始为long对齐
?
?
?
?
SUBa2,a2,#4;往回退一个字
?
?
?
?
MOVsp,a2;建立IRQ堆栈指针
?
?
?
?
MOVa1,#SVC_MODE;建立SVC模式的CPSR
?
?
?
?
MSRCPSR_c,a1;进入SVC模式
?
?
?
?
LDRa4,[pc,#SYS_STACK_PTR-.-8];获得stack指针
?
?
?
?
STRa2,[a4,#0];保存系统堆栈
;
;/*Savethesystemstackpointer.*/
;_tx_thread_system_stack_ptr=(VOID_PTR)(sp);
;
?
?
?
?
LDRa2,[pc,#SYS_STACK_PTR-.-8];获得系统堆栈指针的地址
?
?
?
?
LDRa1,[a2,#0];获得系统堆栈指针
?
?
?
?
ADDa1,a1,#4;增加一个long长度
;
;/*Pickupthefirstavailablememoryaddress.*/
;
;/*Allocatespaceforthetimerthread'sstack.*/
;_tx_timer_stack_start=first_available_memory;
;_tx_timer_stack_size=stack_size;
;_tx_timer_priority=0;
;
?
?
?
?
LDRa2,[pc,#TIMER_STACK-.-8];获得定时堆栈指针地址
?
?
?
?
LDRa4,[pc,#TIMER_STACK_SIZE-.-8];获得定时堆栈大小地址
?
?
?
?
LDRa3,[pc,#TIM_STACK_SIZE-.-8];获得实际定时堆栈大小
?
?
?
?
STRa1,[a2,#0];将定时堆栈的基地址放在堆栈指针地址所对应的内存中
?
?
?
?
STRa3,[a4,#0];存储定时器堆栈大小
?
?
?
?
ADDa1,a1,a3;新的空内存地址
?
?
?
?
?
LDRa2,[pc,#TIMER_PRIORITY-.-8];获得定时器优先级地址
?
?
?
?
?
MOVa3,#0;获得定时器线程优先级
?
?
?
?
STRa3,[a2,#0];存储定时器线程优先级
;/*保存第一个变量内存地址.*/
;_tx_initialize_unused_memory=(VOID_PTR)SystemStack+TimerStack;
;
?
?
?
?
LDRa3,[pc,#UNUSED_MEMORY-.-8];获得没有使用的内存指针地址
?
?
?
?
STRa1,[a3,#0];保存第一个空内存地址
;/*建立周期性的定时中断.*/
?
?
?
?
STMDB{LR}?
?
?
?
?
?
?
?
?
?
?
?
//让lr入栈,保护lr
?
?
?
?
BL?
?
?
?
TargetInit?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
//TargetInit()为C语言编写的中断定时函数
?
?
?
?
LDMIA{lr}?
?
?
?
?
?
?
?
?
?
?
?
//让lr出栈
?
?
?
?
在这里加上ARM定时器已实现周期性的中断
;/*Done,returntocaller.*/
;
?
?
?
?
MOVpc,lr;Returntocaller
;}
__tx_irq_handler
所属文件?
?
?
?
调用者?
?
?
?
开关量
tx_till.s?
?
?
?
IRQ中断?
?
?
?
无
该函数是在定时中断后调用,该函数调用了_tx_thread_context_save函数(包含在tx_tcs.s中),该函数又调用到__tx_irq_processing_return函数处(包含在tx_till.s)
?
?
?
?
EXPORT__tx_irq_handler
?
?
?
?
?
EXPORT__tx_irq_processing_return
__tx_irq_handler
?
;
?
;/*调用函数保存线程上下文环境.*/
?
?
?
?
?
B_tx_thread_context_save
__tx_irq_processing_return
?
;
;/*AtthispointexecutionisstillintheIRQmode.TheCPSR,pointof
;interrupt,andallCscratchregistersareavailableforuse.In
;addition,IRQinterruptsmaybere-enabled-withcertainrestrictions-
;ifnestedIRQinterruptsaredesired.Interruptsmaybere-enabledover
;smallcodesequenceswherelrissavedbeforeenablinginterruptsand
;restoredafterinterruptsareagaindisabled.*/
?
;
;/*Fordebugpurpose,executethetimerinterruptprocessinghere.In
;arealsystem,somekindofstatusindicationwouldhavetobechecked
?
;beforethetimerinterrupthandlercouldbecalled.*/
?
;
BL?
?
?
?
?
?
?
?
clearflag?
?
?
?
?
?
?
?
;清除中断标志位很重要(自己移植时加的,位置是否恰当?
)
?
?
?
?
?
BL_tx_timer_interrupt;定时中断处理函数
?
;
?
;/*系统线程上下文环境恢复函数*/
?
?
?
?
?
B_tx_thread_context_restore
_tx_timer_interrupt
所属文件?
?
?
?
调用者?
?
?
?
开关量
tx_timin.s?
?
?
?
启动代码?
?
?
?
无
该函数主要是中断后将系统时钟加1,时间切片减1。
定时部分比较多,没有完全看明白。
IMPORT_tx_timer_time_slice
?
?
?
?
IMPORT_tx_timer_system_clock
?
?
?
?
IMPORT_tx_timer_current_ptr
?
?
?
?
IMPORT_tx_timer_list_start
?
?
?
?
IMPORT_tx_timer_list_end
?
?
?
?
IMPORT_tx_timer_expired_time_slice
?
?
?
?
IMPORT_tx_timer_expired
?
?
?
?
IMPORT_tx_timer_thread
?
?
?
IMPORT_tx_thread_current_ptr
?
?
?
?
IMPORT_tx_thread_time_slice
?
?
?
?
IMPORT_tx_thread_resume
?
?
?
?
IMPORT_tx_thread_preempt_disable
;
?
?
?
?
?
?
?
?
PRESERVE8
?
?
?
?
?
?
?
?
AREA|C$$code|,CODE,READONLY
|x$codeseg|DATA
;VOID_tx_timer_interrupt(VOID)
;{
?
?
?
?
EXPORT_tx_timer_interrupt
_tx_timer_interrupt
;
;/*Uponentrytothisroutine,itisassumedthatcontextsavehasalready
;beencalled,andthereforethecompilerscratchregistersareavailable
;foruse.*/
;
;/*Incrementthesystemclock.*/
;_tx_timer_system_clock++;
;
?
?
?
?
LDRa2,[pc,#SYSTEM_CLOCK-.-8];获得系统时钟地址
?
?
?
?
LDRa1,[a2,#0];获得系统时钟
?
?
?
?
ADDa1,a1,#1;将系统时钟加1
?
?
?
?
STRa1,[a2,#0];存储新的系统时钟时间
;
;/*Testfortime-sliceexpiration.*/
;if(_tx_timer_time_slice)
;{
;
?
?
?
?
LDRa4,[pc,#TIME_SLICE-.-8];获得链表中的定时切片数地址
?
?
?
?
LDRa3,[a4,#0];获得定时切片数的值
?
?
?
?
CMPa3,#0;定时切片是否有效,>0有效,=0无效
?
?
?
?
BEQ__tx_timer_no_time_slice;=0时,跳到__tx_timer_no_time_slice处
;/*时间切片减1.*/
;_tx_timer_time_slice--;
;
?
?
?
?
SUBa3,a3,#1;时间切片值减1
?
?
?
?
STRa3,[a4,#0];存储新的时间切片值
;
;/*检查是否到期.*/
;if(__tx_timer_time_slice==0)
;
?
?
?
?
CMPa3,#0;>0还是=0?
BNE__tx_timer_no_time_slice;如果>0,
;当没有定时切片时,将定时切片数标志位置1,表示链表中没有切片了。
;/*Setthetime-sliceexpiredflag.*/
;_tx_timer_expired_time_slice=TX_TRUE;
;
?
?
?
?
LDRa4,[pc,#EXPIRED_TIME_SLICE-.-8];获得定时切片数是否为0标志地址
?
?
?
?
?
?
?
MOVa1,#1;将标志设为1
?
?
?
?
STRa1,[a4,#0];设立到时标志
;
;}
;
__tx_timer_no_time_slice
;
;/*Testfortimerexpiration.*/
;if(*_tx_timer_current_ptr)
;{
;
LDRa2,[pc,#TIMER_CURRENT_PTR-.-8];获得的是_tx_timer_current_ptr的地址
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
;而TIMER_DECLARETX_INTERNAL_TIMER**_tx_timer_current_ptr
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
;
?
?
?
?
LDRa1,[a2,#0];获得当前的_tx_timer_current_ptr
LDRa3,[a1,#0];获得定时列表的入口定时切片指针
CMPa3,#0;链表中是否有定时切片存在
?
?
?
?
BEQ__tx_timer_no_timer;不存在,调用__tx_timer_no_time将
;_tx_timer_current_ptr++
;
;/*Setexpirationflag.*/
;_tx_timer_expired=TX_TRUE;
;
?
?
?
?
LDRa4,[pc,#EXPIRED-.-8];Pickupexpriationflagaddress
?
?
?
?
MOVa3,#1;Buildexpiredvalue
?
?
?
?
STRa3,[a4,#0];Setexpiredflag
?
?
?
?
B__tx_timer_done;Finishedtimerprocessing
;
;}
;else
;{
__tx_timer_no_timer
;
;/*Notimerexpired,incrementth