📄 os_cpu_a.asm
字号:
;********************************************************************************************************
; uC/OS-II
; The Real-Time Kernel
;
; (c) Copyright 1992-2000, Jean J. Labrosse, Weston, FL
; All Rights Reserved
;
; ZiLOG eZ80-Specific code
;
; File : OS_CPU_A.ASM
; By : Jean J. Labrosse
; Revised : Douglas Beattie Jr. (13-JAN-2004)
; Port Version : V2.00 (for uC/OS-II V2.52 or higher)
;********************************************************************************************************
.ASSUME ADL=1
CPUFREQ EQU 50000000 ;50_MHz crystal
OS_TICKS_PER_SEC EQU 20 ;this should match OS_TICKS_PER_SEC in OS_CFG.H
MS_TIMER_INT EQU 1 ;Set to '1' to enable millisecond timer ISR
PUBLIC _OSStartHighRdy
PUBLIC _OSCtxSw
PUBLIC _OSIntCtxSw
PUBLIC _OSTickISR
PUBLIC _tick_timer_start
PUBLIC _ms_timer_start
PUBLIC _init_tick_timer
PUBLIC _init_ms_timer
EXTERN _OSTCBCur
EXTERN _OSTCBHighRdy
EXTERN _OSTaskSwHook
EXTERN _OSPrioHighRdy
EXTERN _OSPrioCur
EXTERN _OSRunning
EXTERN _OSIntNesting
EXTERN _OSTimeTick
EXTERN _OSIntExit
.INCLUDE "eZ80F91.inc"
.ASSUME ADL=1
;*********************************************************************************************************
; START MULTITASKING
; void OSStartHighRdy(void)
;*********************************************************************************************************
_OSStartHighRdy:
NOP
; OSTaskSwHook();
CALL _OSTaskSwHook
; OSRunning = TRUE;
LD A,1
LD (_OSRunning),A
; SP = OSTCBHighRdy->OSTCBStkPtr;
LD HL,(_OSTCBHighRdy)
LD HL,(HL)
LD SP,HL
; Pop task's registers
POP IY
POP IX
EX AF,AF'
EXX
POP HL
POP DE
POP BC
POP AF
EX AF,AF'
EXX
POP HL
POP DE
POP BC
POP AF
; Run task
;EI ;;<<<
RETI
;*********************************************************************************************************
; PERFORM A CONTEXT SWITCH (From task level)
; void OSCtxSw(void)
;*********************************************************************************************************
_OSCtxSw:
PUSH AF ; Save current task's context
PUSH BC
PUSH DE
PUSH HL
EX AF,AF'
EXX
PUSH AF
PUSH BC
PUSH DE
PUSH HL
EX AF,AF'
EXX
PUSH IX
PUSH IY
;OSTCBCur->OSTCBStkPtr = StackPointer;
LD HL,0
ADD HL,SP
EX DE,HL
LD HL,(_OSTCBCur)
LD (HL),DE
;CONTINUE WITH CONTEXT SWITCH...
;*********************************************************************************************************
; PERFORM A CONTEXT SWITCH (From an ISR)
; void OSIntCtxSw(void)
;*********************************************************************************************************
_OSIntCtxSw:
; OSTaskSwHook();
CALL _OSTaskSwHook
; OSPrioCur = OSPrioHighRdy;
LD A,(_OSPrioHighRdy)
LD (_OSPrioCur),A
; OSTCBCur = OSTCBHighRdy;
LD HL,(_OSTCBHighRdy)
LD (_OSTCBCur),HL
; SP = OSTCBHighRdy->OSTCBStkPtr;
LD HL,(HL)
LD SP,HL
; Restore task's context
POP IY
POP IX
EX AF,AF'
EXX
POP HL
POP DE
POP BC
POP AF
EX AF,AF'
EXX
POP HL
POP DE
POP BC
POP AF
; Return to new task
;EI ;;<<<
RETI
;*********************************************************************************************************
; TICK ISR
; void OSTickISR (void)
;
; Notes: 1) This implementation assumes that the TICK interrupt will be generated by a TIMER
; 2) Don't forget to clear the interrupt source
;*********************************************************************************************************
_OSTickISR:
PUSH AF ; Save registers
PUSH BC
PUSH DE
PUSH HL
EX AF,AF'
EXX
PUSH AF
PUSH BC
PUSH DE
PUSH HL
EX AF,AF'
EXX
PUSH IX
PUSH IY
;
; Notify uC/OS-II about ISR
;OSIntNesting++
LD HL,_OSIntNesting
LD A,(HL)
INC A
LD (HL),A
; if (OSIntNesting == 1)
CP 1
JR NZ,$F
; OSTCBCur->OSTCBStkPtr = StackPointer
LD HL,0
ADD HL,SP
EX DE,HL
LD HL,(_OSTCBCur)
LD (HL),DE
;
; Clear Timer Interrupt HERE!
$$
IN0 A,(TMR2_IIR) ; Clear timer interrupt flag
;>>>> Optionally re-enable interrupts for higher priority devices
;EI
CALL _OSTimeTick ; Handle TICK interrupt
;
CALL _OSIntExit ; Tell uC/OS-II about end of ISR
;??re-enable tick timer
IN0 A,(TMR2_CTL) ; read Timer 2 Control Register
OR 01h ; just in case, timer activate
OUT0 (TMR2_CTL),A ; write Timer 2 Control Register
POP IY ; Restore task's context
POP IX
EX AF,AF'
EXX
POP HL
POP DE
POP BC
POP AF
EX AF,AF'
EXX
POP HL
POP DE
POP BC
POP AF
;
EI
RETI ; Return to interrupted task
;*********************************************************************************************************
; YOUR ISR
; void ???ISR (void)
;
; Notes : 1) Don't forget to clear the interrupt source
;*********************************************************************************************************
comment ~
YourISR:
PUSH AF ; Save registers
PUSH BC
PUSH DE
PUSH HL
EX AF,AF'
EXX
PUSH AF
PUSH BC
PUSH DE
PUSH HL
EX AF,AF'
EXX
PUSH IX
PUSH IY
;
; Notify uC/OS-II about ISR
;OSIntNesting++
LD HL,_OSIntNesting
LD A,(HL)
INC A
LD (HL),A
; if (OSIntNesting == 1)
CP 1
JR NZ,$F
; OSTCBCur->OSTCBStkPtr = StackPointer
LD HL,0
ADD HL,SP
EX DE,HL
LD HL,(_OSTCBCur)
LD (HL),DE
;
;
; CALL YourISRHandler
;------------------------------------------------------------
; clear interrupt source;
;------------------------------------------------------------
CALL _OSIntExit
;
POP IY ; Restore task's context
POP IX
EX AF,AF'
EXX
POP HL
POP DE
POP BC
POP AF
EX AF,AF'
EXX
POP HL
POP DE
POP BC
POP AF
;
EI
RETI ; Return to interrupted task
;
~ endcomment
PUBLIC _prt_1_isr
IF MS_TIMER_INT
;#################################################################
ms_timer_ISR:
_prt_1_isr:
PUSH AF
IN0 A,(TMR1_IIR) ; Clear timer interrupt flag
PUSH HL
LD HL,(_ms_ticks)
INC HL
LD (_ms_ticks),HL
POP HL
IN0 A,(TMR1_CTL) ; read Timer 4 Control Register
OR 01h ; just in case, timer activate
OUT0 (TMR1_CTL),A ; write Timer 4 Control Register
POP AF
EI
RETI
ms_timer_ISR_size EQU $-ms_timer_ISR
;#################################################################
ELSE
_prt_1_isr:
ENDIF
NULLINT ;;RET
NOP
EI
RETI
;*********************************************************************************************************
; Six timers...
; Timer 0:
; Timer 1: RTOS 'tick' heartbeat
; Timer 2: Reserved, not used
; Timer 3: Reserved, not used
; Timer 4: Reserved, not used
; Timer 5: millisecond-resolution timer
_tick_timer_start:
LD A,01h ;INTs for end-of-count
OUT0 (TMR2_IER),A ; set Interrupt-Enable Register
IN0 A,(TMR2_CTL) ; read Timer 2 Control Register
OR 01h ; INTs on, timer activate
OUT0 (TMR2_CTL),A ; write Timer 2 Control Register
RET
_ms_timer_start:
IF MS_TIMER_INT
LD A,01h ;INTs for end-of-count
OUT0 (TMR1_IER),A ; set Interrupt-Enable Register
IN0 A,(TMR1_CTL) ; read Timer 1 Control Register
OR 01h ; INTs on, timer activate
OUT0 (TMR1_CTL),A ; write Timer 1 Control Register
ELSE
NOP
ENDIF
RET
_init_tick_timer:
TICK_DIVISOR EQU ((CPUFREQ/16)/OS_TICKS_PER_SEC) ;tick divisor
LD A,10010100b ; PHI divide-by-64, continuous.
; INTs off, not yet running
OUT0 (TMR2_CTL),A ; write Timer 2 Control Register
LD A,HIGH(TICK_DIVISOR)
OUT0 (TMR2_RR_H),A ; set Reload Register, MSB
LD A,LOW(TICK_DIVISOR)
OUT0 (TMR2_RR_L),A ; set Reload Register, LSB
RET
_init_ms_timer:
IF MS_TIMER_INT
; ********************************************************
; ** Set up a 10-microsecond-resolution timer on TMR1
; ** with interrupts, this will produce 100,000 INTs/sec.
; ** The corresponding ISR simply increments a 24-bit
; ** variable, for "current milliseconds elapsed" value.
;
; prescale=16
MS_DIVISOR_10u EQU ((CPUFREQ/16)/100000) ;10-microsecond divisor
LD A,10001100b ; PHI/16, reload, continuous,
; INTs off, not yet running
OUT0 (TMR1_CTL),A ; write Timer 4 Control Register
LD A,HIGH(MS_DIVISOR_10u)
OUT0 (TMR1_RR_H),A ; set Reload Register, MSB
LD A,LOW(MS_DIVISOR_10u)
OUT0 (TMR1_RR_L),A ; set Reload Register, LSB
ELSE
MS_DIVISOR EQU ((CPUFREQ/16)/2000) ;milliseconds divisor
ENDIF
RET
SEGMENT BSS
PUBLIC _ms_ticks
_ms_ticks:
DS 3
;*********************************************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -