📄 sch.s
字号:
/** * Copyright (c) 2006-2008 iWESUN (ShenZhen) Inf. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the AvrcX MTOS * * Author: Winter Hu <winter.hu@gmail.com> * Create: Nov 24, 2006 *//*Changlog:Jan 4, 2007, Re-write sleep in assembler Modify method "prologue" to avoid using r25:r24*/#include "common.h"#include "scheduler.h" _MODULE(scheduler) _EXTERN(kernel) /** * Create the task PID of specified TCB * * @param TCB*, r25:r24 * @return PID*, r25:r24 * @see INTERFACE PID* createTask(PCB*) * * @regs: r0, r22, r23, r24, r25, X, Z */ _PUBLIC(create_task)create_task: movw Zl, _p1l rcall lpm_inc mov Xl, r0 rcall lpm_inc mov Xh, r0 ; Get task stack point rcall lpm_inc st X, r0 rcall lpm_inc st -X, r0 ; Push task entry point ldi _p1l, 0 ldi _p1h, 33 ; Push 32 regs + SREG1: st -X, _p1l dec _p1h brne 1b sbiw Xl, 1 ; SP rcall lpm_inc mov _r1l, r0 rcall lpm_inc mov _r1h, r0 ; Get PCB --> r25:r24 rcall lpm_inc mov _r2l, r0 rcall lpm_inc mov _r2h, r0 ; Get PID --> r23:r22 rcall lpm_inc ; Get predefine priority --> r0 mov r1, r0 ; priority --> r1 rcall lpm_inc ; Get predefine tmslices --> r0 movw Zl, _r1l ; PCB --> Z std Z+PCB_PRIORITY, r1 ; Set PCB priority std Z+PCB_TMSLICES, r0 ; Set PCB tmslices std Z+PCB_CONTEXT+0, Xl std Z+PCB_CONTEXT+1, Xh ; Set PCB Context movw Zl, _r2l ; PID --> Z std Z+NODE_PRIORITY, r0 ; Set PID node priority std Z+NODE_PDATA_LO, _r1l std Z+NODE_PDATA_HI, _r1h ; Set PID node pData point to PCB ldi _tmp1, NULL std Z+NODE_PNEXT_LO, _tmp1 std Z+NODE_PNEXT_HI, _tmp1 movw _r1l, Zl ; PID --> _r1l clr r1 ; __zero_reg__ of GCC ret lpm_inc: lpm adiw Zl, 1 ret/** * Pushes entire register context onto the current stack * * void prologue(void) * ASSUMES: SysLevel >= 0, running on kernel stack * REGS: r0, r24, r25, X, Y, Z */ _PUBLIC(prologue)prologue: push r1 push Zh push Zl push Yh push Yl in r1, _SFR_IO_ADDR(SREG) ldi Zl, lo8(kernel) ldi Zh, hi8(kernel) ; Get kernel --> Z ldd Yl, Z+KERN_SYSLEVEL subi Yl, lo8(-1) ; Carry set if results 0 std Z+KERN_SYSLEVEL, Yl brcs saveContext ldd Yl, Z+KERN_RUNNING+0 ldd Yh, Z+KERN_RUNNING+1 or Yh, Yl ; Test kernel.Running brne saveContext ;; IDLE in Yl, _SFR_IO_ADDR(SPL) in Yh, _SFR_IO_ADDR(SPH) ldd Zh, Y+6 ldd Zl, Y+7 ; Get return address adiw Yl, 9 out _SFR_IO_ADDR(SPL), Yl out _SFR_IO_ADDR(SPH), Yh clr __zero_reg__ ijmpsaveContext: push Xh push Xl push r25 push r24 push r23 push r22 push r21 push r20 push r19 push r18 push r17 push r16 push r15 push r14 push r13 push r12 push r11 push r10 push r9 push r8 push r7 push r6 push r5 push r4 push r3 push r2 in Yl, _SFR_IO_ADDR(SPL) in Yh, _SFR_IO_ADDR(SPH) ldd _p4h, Y+32 ldd _p4l, Y+33 ; Get Prologue caller return address std Y+32, r1 ; save SREG std Y+33, r0 ; save r0 ;; End save task context brcs alreadyInKernel ; from above ldd Xl, Z+KERN_RUNNING+0 ldd Xh, Z+KERN_RUNNING+1 movw Zl, Xl ; Get kernel.PID --> Z ldd Xl, Z+NODE_PDATA_LO ldd Xh, Z+NODE_PDATA_HI movw Zl, Xl ; Get kernel.PID.pcb --> Z std Z+PCB_CONTEXT+0, Yl std Z+PCB_CONTEXT+1, Yh ; Save task SP ldi Zl, lo8(kernel) ldi Zh, hi8(kernel) ldd Yl, Z+KERN_CONTEXT+0 ldd Yh, Z+KERN_CONTEXT+1 ; Get kernel.Context out _SFR_IO_ADDR(SPL), Yl out _SFR_IO_ADDR(SPH), Yh ; Change to kernel stackalreadyInKernel: clr __zero_reg__ ; GCC movw Zl, _p4l ; Prologue caller return address --> Z ijmp /** * Restore previous context (kernel or user) * * void epilogue(void) * ASSUMES: SysLevel >= 0, running on kernel stack * REGS: */ _PUBLIC(epilogue)epilogue: pop r24 pop r24 ; This method never return caller _PUBLIC(_epilogue)_epilogue: cli ldi Zl, lo8(kernel) ldi Zh, hi8(kernel) ldd Xl, Z+KERN_SYSLEVEL dec Xl std Z+KERN_SYSLEVEL, Xl brge stillInKernel ldd Xl, Z+KERN_RUNNING+0 ldd Xh, Z+KERN_RUNNING+1 adiw Xl, 0 breq idleTask movw Zl, Xl ; Get kernel.PID --> Z ldd Xl, Z+NODE_PDATA_LO ldd Xh, Z+NODE_PDATA_HI movw Zl, Xl ; Get kernel.PID.pcb --> Z ldd Yl, Z+PCB_CONTEXT+0 ldd Yh, Z+PCB_CONTEXT+1 out _SFR_IO_ADDR(SPL), Yl out _SFR_IO_ADDR(SPH), Yh ; Set stack to current taskstillInKernel: pop r2 pop r3 pop r4 pop r5 pop r6 pop r7 pop r8 pop r9 pop r10 pop r11 pop r12 pop r13 pop r14 pop r15 pop r16 pop r17 pop r18 pop r19 pop r20 pop r21 pop r22 pop r23 pop r24 pop r25 pop Xl pop Xh pop Yl pop Yh pop Zl pop Zh pop r1 pop r0 out _SFR_IO_ADDR(SREG), r0 pop r0 retiidleTask: sei nop ; sleep rjmp idleTask /** * Causes the currently executing task to temporarily pause in TimQueue * until delay expire. * * @param unsigned int, Ticks for sleeping */ _PUBLIC(sleep)sleep: cli rcall prologue movw _p2l, _p1l lds _p1l, kernel+KERN_RUNNING+0 lds _p1h, kernel+KERN_RUNNING+1 rcall delay_task rcall swapping rjmp _epilogue _ENDMOD
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -