threadx学习笔记
t h r e a d x学习笔记(总23页) -CAL-FENGHAI.-(YICAI)-Company One1
-CAL-本页仅作为文档封面,使用请直接删除
threadx学习笔记(一)
tx_ill.s文件用来处理初始化过程中的汇编语言,它是面向处理器和开发工具的。
Void_tx_initialize_low_level{
1、CPSCR|= FIQ_ MODE,SET SP_fiq;
2、CPSCR|=IRQ_MODE,SET SP_irp;
3、CPSCR|=SVC_MODE,SET SP_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,PUSH R0-R3,CPSR,R14 in IRQ stack,B
__tx_irq_processing_return;
3、else if _tx_thread_current_ptr=0判断是否有线程正在运行,if not ,B _tx_irq_processing_return;
4、else,PU SH Context_irq in thread’s stack,SP_thread=new SP,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,POP R0-R3,CPSR,R14 from IRQ stack,BX R14;
2、else if _tx_thread_current_ptr=0?if =0
CPSR|=VC_MODE,CPSR|=TX_INT_ENABLE,跳到线程调度程序B _tx_thread_schedule;
3、if!=0,则判断线程抢占是否禁止 if
_tx_thread_preempt_disable=0?if!=0,POP Context_irq from thread’s stack,BX R14;
4、if=0,_tx_timer_time_slice=new
value,_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、PUSH Context_request:in thread’s stack,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_p
tr;
3、_tx_thread_current_ptr-
>TX_run_count++,_tx_timer_time_slice=_tx_thread_current_ptr-
>tx_time_slice;
4、If线程堆栈的中断类型=1,restore Context_irq,else restore
Context_request;
}
Tx_tic.s用于开中断和关中断。
Unint _tx_thread_interrupt_control(unint new _posture){
1、R1=CPSR;
2、SWI;
3、CPSR|=RO=new posture;
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、中断地址存入线程调用的入口地址PUSH function_ptr;
3、R0-R12,R14的初始值都设置为0,PUSH初始值;
4、要存入堆栈的CPSR值设置为用户模式,开中断,标志位清零,
R1=USER_MODE,PUSH R1;
5、Thread_ptr->sp=new SP;
}
当处理一个低级的中断时,tx_tpc.s决定是否发生抢占,它是可选的,大多数端口都用不到。TX_TIMIN.S负责处理定时中断。这两个函数只要将它们翻译成相应ARM汇编语言就可以了。
threadx学习笔记(二)-1
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()
void tx_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(堆栈指针)*/
;/* We must be in SVC mode at this point! */
;
LDR a2,=|Image$$ZI$$Limit|; Get end of non-initialized RAM area
LDR a3,[pc,#FIQ_STACK_SIZE-.-8];获得FIO堆栈地址(这里没有弄明白,有待)
MOV a1,#FIQ_MODE ;设置FIQ_MODE
MSR CPSR_c, a1 ;进入FIQ模式
ADD a2, a2, a3 ;计算FIQ堆栈的开始
BIC a2, a2,#3 ;将a2的低两位清零确保堆栈的的开始为long对齐
SUB a2, a2,#4 ;往回退一个字
MOV sp, a2 ;建立FIQ 堆栈指针(即FIQ模式的sp)
MOV sl,#0 ; Clear sl(R10)
MOV fp,#0 ; Clear fp(R11)
LDR a3,[pc,#SYS_STACK_SIZE-.-8]
;获得 IRQ (system stack size)
MOV a1,#IRQ_MODE ;建立IRQ模式的 CPSR
MSR CPSR_c, a1 ;进入IRQ模式
ADD a2, a2, a3 ;计算IRQ stack的开始
BIC a2, a2,#3 ;将a2的低两位清零确保堆栈的的开始为long对齐SUB a2, a2,#4 ;往回退一个字
MOV sp, a2 ;建立 IRQ 堆栈指针
MOV a1,#SVC_MODE ;建立SVC模式的CPSR
MSR CPSR_c, a1 ;进入 SVC模式
LDR a4,[pc,#SYS_STACK_PTR-.-8];获得stack 指针
STR a2,[a4,#0];保存系统堆栈
;
;/* Save the system stack pointer. */
; _tx_thread_system_stack_ptr =(VOID_PTR)(sp);
;
LDR a2,[pc,#SYS_STACK_PTR-.-8];获得系统堆栈指针的地址LDR a1,[a2,#0];获得系统堆栈指针
ADD a1, a1,#4 ;增加一个long长度
;
;/* Pickup the first available memory address. */
;
;/* Allocate space for the timer thread's stack. */
; _tx_timer_stack_start = first_available_memory;
; _tx_timer_stack_size = stack_size;
; _tx_timer_priority = 0;
;
LDR a2,[pc,#TIMER_STACK-.-8];获得定时堆栈指针地址
LDR a4,[pc,#TIMER_STACK_SIZE-.-8];获得定时堆栈大小地址
LDR a3,[pc,#TIM_STACK_SIZE-.-8];获得实际定时堆栈大小
STR a1,[a2,#0];将定时堆栈的基地址放在堆栈指针地址所对应的内存中
STR a3,[a4,#0];存储定时器堆栈大小
ADD a1, a1, a3 ;新的空内存地址
LDR a2,[pc,#TIMER_PRIORITY-.-8];获得定时器优先级地址
MOV a3,#0 ;获得定时器线程优先级
STR a3,[a2,#0];存储定时器线程优先级
;/*保存第一个变量内存地址. */
; _tx_initialize_unused_memory =(VOID_PTR)System Stack+ Timer Stack;
;
LDR a3,[pc,#UNUSED_MEMORY-.-8];获得没有使用的内存指针地址
STR a1,[a3,#0];保存第一个空内存地址
;/* 建立周期性的定时中断. */
STMDB {LR}//让lr入栈,保护lr
BLTargetInit//TargetInit()为C语言编写的中断定时函数
LDMIA {lr}//让lr出栈
在这里加上ARM定时器已实现周期性的中断
;/* Done, return to caller. */
;
MOV pc, lr ;Return to caller
;}
__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
;
;/* At this point execution is still in the IRQ mode. The CPSR, point of ; interrupt, and all C scratch registers are available for use. In
; addition, IRQ interrupts may be re-enabled - with certain restrictions -; if nested IRQ interrupts are desired. Interrupts may be re-enabled over ; small code sequences where lr is saved before enabling interrupts and ; restored after interrupts are again disabled. */
;
;/* For debug purpose, execute the timer interrupt processing here. In
; a real system, some kind of status indication would have to be checked ; before the timer interrupt handler could be called. */
;
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
;
;/* Upon entry to this routine, it is assumed that context save has already
; been called, and therefore the compiler scratch registers are available
; for use. */
;
;/* Increment the system clock. */
; _tx_timer_system_clock++;
;
LDR a2,[pc,#SYSTEM_CLOCK-.-8];获得系统时钟地址
LDR a1,[a2,#0];获得系统时钟
ADD a1, a1,#1 ;将系统时钟加1
STR a1,[a2,#0];存储新的系统时钟时间
;
;/* Test for time-slice expiration. */
;if(_tx_timer_time_slice)
;{
;
LDR a4,[pc,#TIME_SLICE-.-8];获得链表中的定时切片数地址
LDR a3,[a4,#0];获得定时切片数的值
CMP a3,#0 ;定时切片是否有效,>0有效,=0无效
BEQ __tx_timer_no_time_slice ;=0时,跳到__tx_timer_no_time_slice处;/* 时间切片减1. */
; _tx_timer_time_slice--;
;
SUB a3, a3,#1 ;时间切片值减1
STR a3,[a4,#0];存储新的时间切片值
;
;/* 检查是否到期. */
;if(__tx_timer_time_slice == 0)
;
CMP a3,#0 ;>0还是=0?
BNE __tx_timer_no_time_slice ;如果>0,
;当没有定时切片时,将定时切片数标志位置1,表示链表中没有切片了。
;/* Set the time-slice expired flag. */
; _tx_timer_expired_time_slice = TX_TRUE;
;
LDR a4,[pc,#EXPIRED_TIME_SLICE-.-8];获得定时切片数是否为0标志地址MOV a1,#1 ;将标志设为1
STR a1,[a4,#0];设立到时标志
;
;}
;
__tx_timer_no_time_slice
;
;/* Test for timer expiration. */
;if(*_tx_timer_current_ptr)
;{
;
LDR a2,[pc,#TIMER_CURRENT_PTR-.-8];获得的是_tx_timer_current_ptr的地址;而TIMER_DECLARE TX_INTERNAL_TIMER **_tx_timer_current_ptr
;
LDR a1,[a2,#0];获得当前的_tx_timer_current_ptr
LDR a3,[a1,#0];获得定时列表的入口定时切片指针
CMP a3,#0 ;链表中是否有定时切片存在
BEQ __tx_timer_no_timer ;不存在,调用__tx_timer_no_time将
;_tx_timer_current_ptr++
;
;/* Set expiration flag. */
; _tx_timer_expired = TX_TRUE;
;
LDR a4,[pc,#EXPIRED-.-8]; Pickup expriation flag address MOV a3,#1 ; Build expired value
STR a3,[a4,#0];Set expired flag
B __tx_timer_done ; Finished timer processing
;
;}
;else
;{
__tx_timer_no_timer
;
;/* No timer expired, increment the timer pointer. */
; _tx_timer_current_ptr++;
;
ADD a1, a1,#4 ; Move to next timer
;
;/* Check for wrap-around. */
;if(_tx_timer_current_ptr == _tx_timer_list_end)
;
LDR a4,[pc,#LIST_END-.-8]; Pickup addr of timer list end LDR a3,[a4,#0]; Pickup list end
CMP a1, a3 ; Are we at list end
BNE __tx_timer_skip_wrap ; No, skip wrap-around logic
;
;/* Wrap to beginning of list. */
; _tx_timer_current_ptr = _tx_timer_list_start;
;
LDR a4,[pc,#LIST_START-.-8]; Pickup addr of timer list start
LDR a1,[a4,#0];Set current pointer to list start
;
__tx_timer_skip_wrap
;
STR a1,[a2,#0]; Store new current timer pointer
;}
;
__tx_timer_done
;
;
;/* See if anything has expired. */
;if((_tx_timer_expired_time_slice)||(_tx_timer_expired))
;{
;
LDR a4,[pc,#EXPIRED_TIME_SLICE-.-8]; Pickup addr of expired flag LDR a3,[a4,#0]; Pickup time-slice expired flag
CMP a3,#0 ; Did a time-slice expire
BNE __tx_something_expired ;If non-zero,time-slice expired
LDR a2,[pc,#EXPIRED-.-8]; Pickup addr of other expired flag
LDR a1,[a2,#0]; Pickup timer expired flag
CMP a1,#0 ; Did a timer expire
BEQ __tx_timer_nothing_expired ; No, nothing expired
;
__tx_something_expired
;
;
STR lr,[sp,#-4]!; Save the lr register on the stack
;
;/* Did a timer expire
*/
;if(_tx_timer_expired)
;{
;
LDR a2,[pc,#EXPIRED-.-8]; Pickup addr of expired flag
LDR a1,[a2,#0]; Pickup timer expired flag
CMP a1,#0 ; Check for timer expiration
BEQ __tx_timer_dont_activate ;If not set, skip timer activation
;
;/* Increment the preempt disable counter in preparation for
; thread resumption. */
; _tx_thread_preempt_disable++;
;
LDR a4,[pc,#PREEMPT_DISABLE-.-8]; Pickup addr of preempt disable LDR a3,[a4,#0]; Pickup actual flag
ADD a3, a3,#1 ; Incrment the preempt disable count
STR a3,[a4,#0]; Store it back
;
;/* Activate the system timer thread. */
; _tx_thread_resume(&_tx_timer_thread);
;
LDR a1,[pc,#TIMER_THREAD-.-8]; Get timer thread control block addr BL _tx_thread_resume ; Call thread resume to wake up the
; timer thread
;
;}
__tx_timer_dont_activate
;
;/* Did time slice expire
*/
;if(_tx_timer_expired_time_slice)
;{
;
LDR a4,[pc,#EXPIRED_TIME_SLICE-.-8]; Pickup addr of time-slice expired LDR a3,[a4,#0]; Pickup the actual flag
CMP a3,#0 ; See if the flag is set
BEQ __tx_timer_not_ts_expiration ; No, skip time-slice processing
;
;/* Time slice interrupted thread. */
;if(!_tx_thread_time_slice())
; _tx_timer_time_slice = _tx_thread_current_ptr -> tx_time_slice;
;
BL _tx_thread_time_slice ; Call time-slice processing
CMP a1,#0 ; Check return status
BNE __tx_timer_not_ts_expiration ;If time-sliced, skip reset processing LDR a2,[pc,#CURRENT_PTR-.-8]; Pickup addr of current thread pointer LDR a1,[a2,#0]; Pickup thread pointer
LDR a3,[a1,#24]; Pickup fresh time-slice for thread
;(a fresh time slice was setup in
; the _tx_thread_time_slice function)
LDR a4,[pc,#TIME_SLICE-.-8]; Pickup addr of time-slice variable
STR a3,[a4,#0]; Setup new time-slice
;
;}
;
__tx_timer_not_ts_expiration
;
LDR a4,[pc,#EXPIRED_TIME_SLICE-.-8]; Pickup address of expired time-slice flag MOV a1,#0 ; Clear value
STR a1,[a4,#0]; Clear time-slice expired flag
;
LDR lr,[sp],#4 ; Recover lr register
;
;}
;
__tx_timer_nothing_expired
;
MOV pc, lr ;Return to caller
;
;}
TIME_SLICE
DCD _tx_timer_time_slice
SYSTEM_CLOCK
DCD _tx_timer_system_clock
TIMER_CURRENT_PTR
DCD _tx_timer_current_ptr
LIST_START
DCD _tx_timer_list_start
LIST_END
DCD _tx_timer_list_end
EXPIRED_TIME_SLICE
DCD _tx_timer_expired_time_slice
EXPIRED
DCD _tx_timer_expired
TIMER_THREAD
DCD _tx_timer_thread
CURRENT_PTR
DCD _tx_thread_current_ptr
THREAD_TIME_SLICE
DCD _tx_thread_time_slice
RESUME
DCD _tx_thread_resume
PREEMPT_DISABLE
DCD _tx_thread_preempt_disable
END
_tx_initialize_high_level()
VOID _tx_initialize_high_level(VOID)
所属文件调用者开关量
tx_ihl.c启动代码无
主要时对一些与硬件无关的变量进行初始化,其中主要实现了线程的初始化;定时的初始化,这里定时也是一个线程,且优先级为最高0;还有对信号量、队列、时间标志、块池、和字节池的初始化。
/*进行一些高级的初始化*/
_tx_initialize_high_level();
VOID _tx_initialize_high_level(VOID)
{
/* Initialize the event log, if enabled. */ TX_EL_INITIALIZE
/* 调用线程初始化函数. */
_tx_thread_initialize();
/* 调用定时初始化函数 */
_tx_timer_initialize();
/* 调用信号量初始化函数 */
_tx_semaphore_initialize();
/* 调用队列初始化函数 */
_tx_queue_initialize();
/* 调用事件标志初始化函数. */
_tx_event_flags_initialize();
/* 调用block pool 初始化函数. */
_tx_block_pool_initialize();
/* 调用byte pool初始化函数. */
_tx_byte_pool_initialize();
}
/* 调用线程初始化函数. */
_tx_thread_initialize();
VOID _tx_thread_initialize(VOID)
所属文件调用者开关量
tx_ti.c启动代码无
此函数主要实现对与线程有关的一些变量进行初始化。
VOID _tx_thread_initialize(VOID)
{
REG_1 UINT i;/* Working index variable */
REG_2 UCHAR set_bit;/* Lowest set bit
*/ H
REG_3 UINT temp;/* Working shift variable
*/
REG_4 UCHAR *lowest_set_ptr;/* Pointer in set bit array
*/
REG_5 TX_THREAD_PTR?*priority_list_ptr;/* Pointer in priority list */
/* Note: the system stack pointer and the system state variables are
initialized by the low and high-level initialization functions,
respectively. */
/* 初始化当前线程指针为空 */
_tx_thread_current_ptr = TX_NULL;
/* 初始化要执行线程指针为空. */
_tx_thread_execute_ptr = TX_NULL;
/* 初始化优先级信息 */
_tx_thread_priority_map = 0;
_tx_thread_preempted_map = 0;
_tx_thread_highest_priority = TX_MAX_PRIORITIES;
/* 初始化the lowest-set bit 表. 这被用来当线程被挂起和从新启动时寻找下一个准备执行的线程 */