1、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_priori
2、t; 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,
3、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,PUSH Context_irq in thread’s stack,SP_thread=new SP,B _tx_irq_processing_return; } 由于R13和R14在不同CPU模式下相应是不同物理寄存器,因此若要得到中断前线程堆栈指针,需要先返回到该线程运营模式,同步禁止中断,取值
4、后再返回到终端模式。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
5、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_schedul
6、e; } 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_pt
7、r=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_DIS
8、ABLE,_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,restore Context_irq,else restore Context_request; } Tx_tic.s用于开中断和关中断。 Unint _tx_thread_interrupt_
9、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_
10、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值设立为顾客模式,开中断,标志位
11、清零,R1=USER_MODE,PUSH R1; 5、 Thread_ptr->sp=new SP; } 当解决一种低档中断时,tx_tpc.s决定与否发生抢占,它是可选,大多数端口都用不到。TX_TIMIN.S负责解决定期中断。这两个函数只要将它们翻译成相应ARM汇编语言就可以了。 threadx学习笔记(二)-1 tx_kernel_enter();进入threadx核 tx_kernel_enter() void tx_kernel_enter(void) 所属文献 调用者 开关量 demo.C 启动代
12、码 无 操作系统一方面从从量表直接进入该函数,在函数此前没有进行任何硬件及软件初始化!该函数重要包括_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_INITIALI
13、ZE_ALMOST_DONE) { /* 没有初始化话执行下面程序 */ /* 设立系统状态变量来表达现正在解决过程中 注意该变量在后边中断嵌套中会使用 */ _tx_thread_system_state = TX_INITIALIZE_IN_PROGRESS; /* 进行某些基本硬件设立,启动程序等 */ _tx_initialize_low_level(); /*进行某些高档初始化*/ _tx_initialize_high_level()
14、 } /*设立系统状态变量来表达现正在解决过程中 注意该变量在后边中断嵌套中会使用*/ _tx_thread_system_state = TX_INITIALIZE_IN_PROGRESS; /* 调用初始化中提供应用程序 把第一种未使用变量地址传送给它 */ tx_application_define(_tx_initialize_unused_memory); /*设立系统壮伟进入线程调度做准备*/ _tx_thread_system_state = TX_INITIALIZE_IS_FINISHED;
15、 /* 进入线程循环开始执行线程 */ _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(); ;/*
16、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
17、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 ;Cle
18、ar 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 堆栈
19、指针 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
20、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
21、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 ;获得定期器线程优先级
22、 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 BL TargetInit
23、 //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中),该函数又调用到_
24、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 o
25、f ;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
26、 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 ;清除中断标志位很重要(自己移植时加,位置
27、与否恰当?) 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_
28、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_thre
29、ad_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
30、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. */
31、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
32、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] ;获得定期切
33、片数与否为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
34、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; ; L
35、DR 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+
36、 ; 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
37、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
38、 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-s
39、lice 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_
40、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
41、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,
42、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
43、 ;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,
44、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
45、 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
46、 ;(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_expirati
47、on ; 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_
48、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_e
49、xpired 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_initializ
50、e_high_level(VOID) 所属文献 调用者 开关量 tx_ihl.c 启动代码 无 重要时对某些与硬件无关变量进行初始化,其中重要实现了线程初始化;定期初始化,这里定期也是一种线程,且优先级为最高0;尚有对信号量、队列、时间标志、块池、和字节池初始化。 /*进行某些高档初始化*/ _tx_initialize_high_level(); VOID _tx_initialize_high_level(VOID) { /* Initialize the event log,if enabled. */ TX






