⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cxsk53s.s90

📁 CMEX source code RTOS for atmel atmega128
💻 S90
字号:
;******************************************************
;
;	Copyright (C) 2002
;	CMX Systems, Inc.
;	12276 San Jose Blvd, #119
;	Jacksonville, FL 32223
;
;	All Rights Reserved
;
; 	CONFIDENTIAL
;*******************************************************
#include "macros.m90"

; for ATMEL AVR processor 
; Note: for 2 byte shorts
; ASSUMES compiled C code with switches -v1 or -v3
; ASSUMES SMALL memory model
; IAR uses the Y register for parameters passing and locals
; CMX uses the Z register for pointer to index through cmx_tcb array
; WORDS (INTS) are store low byte, high byte
; For this K_I_Scheduler, we are going to set up 2 stacks
; one for the system stack and one for the user stack (Using Y reg)

	RSEG	CODE(0)
	CASEON
fwlink		equ	H'00	;forward wait link
bwlink		equ	H'02	;backward wait link
ftlink		equ	H'04	;forward time link
btlink		equ	H'06	;backward time link
tcbstate_low	equ	H'08	;task state    
tcbstate_high	equ	H'09	;task state    
trig		equ	H'0a	;the number of triggers (starts) for task
priority	equ	H'0b	;task priority, 0 is highest
tcbtimer	equ	H'0c	;task countdown delay timer
nxttcb  	equ	H'0e	;ptr to next TCB (task control block)
task_addr	equ	H'10	;address of where task's code begins
stk_start  	equ	H'12	;the task's stack address 
stk_save  	equ	H'14	;the task's stack save address
system_stk_start equ	H'16	;the task's stack address 
system_stk_save  equ	H'18	;the task's stack save address

; tcbstate high byte, 1'st byte of tcbstate
IDLE 		equ	H'01	;task not able to run, no triggers
READY 		equ	H'02	;the task ready to run
RESUME		equ	H'04	;the task ready to run, resume where it left off
RUNNING		equ	H'08	;the task is the running task
TIME		equ	H'10
	
; tcbstate low byte, 2'nd byte of tcbstate
RESOURCE	equ	H'01	;waiting on time
WAIT		equ	H'02	;waiting
SEND_MESG	equ	H'08	;waiting for task that recieved message,to wake me
WAIT_MESG	equ	H'10	;waiting for message
FLAGS		equ	H'20	;waiting on flag
TIME_EXPIRED	equ	H'40	;the time period specified has ellapsed
SEMAPHORE	equ	H'80	;the time period specified has ellapsed

LOW_POWER_ACTIVE equ 0	;set to 1, to enable K_OS_Low_Power_Func function

SLICE_ENABLE equ 1	;set to 1, to enable time slicing code testing

CMXTRACKER_ENABLE EQU 0	;SET TO 1 IF USING CMXTRACKER, otherwise 0

 IF (CMXTRACKER_ENABLE)
	EXTERN	previoustcb
	EXTERN	cmxtracker_in_task
 ENDIF

SAVE_RAMPZ equ 0     ;Set to 1 (one) if you are using a derivative that has this register

	EXTERN	stack_holder 
	EXTERN	interrupt_stack 
	EXTERN	system_interrupt_stack 
	EXTERN	activetcb 
	EXTERN	active_priority
	EXTERN	cmx_tcb 
	EXTERN	K_I_Intrp_Pipe_Out
	EXTERN	K_I_Timer_Task
	EXTERN	K_OS_Low_Power_Func
	EXTERN  TSLICE_SCALE
	EXTERN  SLICE_ON
	EXTERN  tslice_count
	EXTERN	int_count
	EXTERN	locked_out
	EXTERN	cmx_flag1
	EXTERN	ie_holder

	PUBLIC	K_OS_Intrp_Entry
	PUBLIC	K_OS_Intrp_Exit
	PUBLIC	K_I_Sched
	PUBLIC 	K_I_Scheduler
	PUBLIC	K_OS_Enable_Interrupts 
	PUBLIC	K_OS_Disable_Interrupts 
	PUBLIC	K_OS_Save_Interrupts 
	PUBLIC	K_OS_Restore_Interrupts 

	RSEG	CODE

preempted equ H'01	;preemption flag position
do_timer_tsk equ H'02	;timer task flag position
do_time_slice equ H'04	;do time slice, next slice task if possible
slice_enable equ H'08	;time slice enabled
do_coop_sched equ H'10	;cooperative scheduling flag position
do_int_pipe equ H'20	;interrupt pipe needs processing
idle_flag equ H'40	;used by CMX to see if all tasks cannot run
cmx_active equ H'80	;shows that the CMX OS entered

bit_preempted equ 0
bit_do_timer_tsk equ 1
bit_do_time_slice equ 2
bit_slice_enable equ 3
bit_do_coop_sched equ 4
bit_do_int_pipe equ 5
bit_idle_flag equ 6
bit_cmx_active equ 7

K_I_Sched:	       
	ST	-Y,R16	;save R16
        IN      R16,LOW(63)	;get SREG
        ST      -Y,R16	;save SREG
sched_x:
	ST	-Y,R31	;save rest of registers
	ST	-Y,R30
;	ST	-Y,R29	;do not save Y
;	ST	-Y,R28
	ST	-Y,R27
	ST	-Y,R26
	ST	-Y,R25
	ST	-Y,R24
	ST	-Y,R23
	ST	-Y,R22
	ST	-Y,R21
	ST	-Y,R20
	ST	-Y,R19
	ST	-Y,R18
	ST	-Y,R17
	ST	-Y,R15
	ST	-Y,R14
	ST	-Y,R13
	ST	-Y,R12
	ST	-Y,R11
	ST	-Y,R10
	ST	-Y,R9
	ST	-Y,R8
	ST	-Y,R7
	ST	-Y,R6
	ST	-Y,R5
	ST	-Y,R4
	ST	-Y,R3
	ST	-Y,R2
	ST	-Y,R1
	ST	-Y,R0
 IF SAVE_RAMPZ > 0
        IN      R16,LOW(RAMPZ)	;get RAMPZ
        ST      -Y,R16	;save RAMPZ
 ENDIF
sched_int:
;	Z REG is used for activetcb pointer
	LDS     R30,LWRD(activetcb)	;get current active task tcb
	LDS     R31,LWRD((activetcb+1))
	LDD	R16,Z+tcbstate_high
	CPI	R16,RUNNING	;see if task was running
	BREQ	set_resume	;yes, so set flag indicating the task should
				;finish its code, because the interrupt
				;preempted it, during a task locked out
	
	LDI	R16,H'FF		
	STS	LWRD(active_priority),R16	;set priority to lowest.
	RJMP	sched_cont
set_resume:
	LDI	R16,RESUME	;save task's new state
	STD	Z+tcbstate_high,R16
sched_cont:
	STD	Z+stk_save,R28	;save task's current user stack address
	STD	Z+stk_save+1,R29
	IN	R20,0x3D	;GET SYSTEM STACK
	IN	R21,0x3E
	STD	Z+system_stk_save,R20	;save task's current system stack address
	STD	Z+system_stk_save+1,R21
K_I_Scheduler:	
	CLI	;turn interrupts off
	LDS     R28,LWRD(interrupt_stack)	;load in interrupt and K_I_Scheduler user stack
	LDS     R29,LWRD((interrupt_stack+1))
	LDS     R20,LWRD(system_interrupt_stack)	;load in interrupt and K_I_Scheduler system stack
	LDS     R21,LWRD((system_interrupt_stack+1))
	OUT	0x3D,R20
	OUT	0x3E,R21
	LDI	R16,H'01		
	STS	LWRD(int_count),R16	;set int count to 1, for using stack
	STS	LWRD(locked_out),R16	;set locked out to 1, critical region
sched_again:
;
	SEI	;enable interrupts
rescan1:
	LDS	R16,LWRD(cmx_flag1)	;Get CMX flags
	SBRS	R16,LOW(bit_do_timer_tsk)	;see if K_I_Timer_Task needs to be called
	RJMP	rescan2			;No, jump
	CLI	;turn interrupts off	;yes, turn interrupts off
	LDS	R16,LWRD(cmx_flag1)	;get flags again
	CBR	R16,do_timer_tsk	;clear respective bit
	STS	LWRD(cmx_flag1),R16	;store it
	SEI	;enable interrupts
	PUSH	R30
	PUSH	R31
	CALL	K_I_Timer_Task	;call CMX timer func. that will dec. timer
	POP	R31
	POP	R30
rescan2:
	LDS	R16,LWRD(cmx_flag1)	;Get CMX flags
	SBRS	R16,LOW(bit_do_int_pipe)	;see if K_I_Intrp_Pipe_Out needs to be called
	RJMP	rescan4			;No, jump
	PUSH	R30			;yes
	PUSH	R31
	CALL	K_I_Intrp_Pipe_Out	;go process interrupt pipe contents
	POP	R31
	POP	R30
rescan4:
	LDS	R16,LWRD(cmx_flag1)	;Get CMX flags
	SBRS	R16,LOW(bit_preempted)	;see if preempted flag set
	RJMP	rescan5			;No, jump
	CLI				;yes, turn interrupts off
	LDS	R16,LWRD(cmx_flag1)	;get flags again
	CBR	R16,(preempted | do_coop_sched | do_time_slice | slice_enable)
	SBR	R16,idle_flag
	STS	LWRD(cmx_flag1),R16
	SEI	;enable interrupts
	LDS	R30,LWRD(cmx_tcb+nxttcb)	;load in highest priority user task
	LDS	R31,LWRD(cmx_tcb+nxttcb+1)
	RJMP	midpaus2		;now go see if ready
rescan5:
	LDS	R16,LWRD(cmx_flag1)		;Get CMX flags
	SBRS	R16,LOW(bit_do_coop_sched)	;see if preempted flag set
	RJMP	rescan6				;No, jump
	CLI					;yes, turn interrupts off
	LDS	R16,LWRD(cmx_flag1)		;get flags again
	CBR	R16,(do_coop_sched | do_time_slice | slice_enable)
	STS	LWRD(cmx_flag1),R16
	SEI	;enable interrupts
	RJMP	findready		;get next task in line
rescan6:
 IF SLICE_ENABLE > 0			
	LDS	R16,LWRD(cmx_flag1)		;Get CMX flags
	SBRS	R16,LOW(bit_do_time_slice)	;see if time slice flag set
	RJMP	midpaus2			;No, jump
	CLI	;turn interrupts off
	LDS	R16,LWRD(cmx_flag1)
	CBR	R16,do_time_slice		;clear bit
	STS	LWRD(cmx_flag1),R16
	SEI	;enable interrupts
	RJMP	findready		;get next task in line
 ENDIF
midpaus2:
	LDD	R18,Z+tcbstate_high	;get task state
	ANDI	R18,(RESUME | READY)	;see if capable of running.
	BRNE	task_resume		;yes, let task run
findready:
	LDD	R16,Z+nxttcb	;get task state
	LDD	R17,Z+nxttcb+1	;get task state
	MOV	R30,R16
	MOV	R31,R17
	CPI	R16,LOW(cmx_tcb)	;see if at end of linked list	
	BRNE	midpaus2	;no, go test this task to see if runnable
	CPI	R17,HIGH(cmx_tcb)	;see if at end of linked list
	BRNE	midpaus2	;no, go test this task to see if runnable
 IF LOW_POWER_ACTIVE > 0
	LDS	R16,LWRD(cmx_flag1)	;get flags
	SBRS	R16,LOW(bit_idle_flag)	;have we traveled down complete link list?
	RJMP	no_power_down	;no, then no power down
power_down:
	CALL	@K_OS_Low_Power_Func	;go to user written low power mode
no_power_down:
 ENDIF
	LDS	R30,LWRD(cmx_tcb+nxttcb)	;load in highest priority user task
	LDS	R31,LWRD(cmx_tcb+nxttcb+1)
	RJMP 	rescan1		;go test flags again
task_resume:	
	LDD	R0,Z+priority	;get task's priority
	STS	LWRD(active_priority),R0	;load it into global variable.
 IF SLICE_ENABLE > 0			
	LDS	R16,LWRD(SLICE_ON)	;see if time slicing enabled
	CPI	R16,0		
	BREQ	no_slice	;no, exit
	LDS	R16,LWRD(cmx_flag1)
	SBRC	R16,LOW(bit_slice_enable)	;test slice bit
	RJMP	no_slice		;already set, good
	CLI	;turn interrupts off
	LDS	R16,LWRD(cmx_flag1)
	SBR	R16,slice_enable	;set it
	STS	LWRD(cmx_flag1),R16
	SEI	;enable interrupts
	LDS	R16,LWRD(TSLICE_SCALE)	;now load time slice count
	STS	LWRD(tslice_count),R16
no_slice:
 ENDIF
	STS     LWRD(activetcb),R30	;store active task tcb
	STS     LWRD((activetcb+1)),R31
 IF CMXTRACKER_ENABLE > 0			
	LDS     R20,LWRD(previoustcb)	;get previous active task tcb
	LDS     R21,LWRD((previoustcb+1))
	CP	R30,R20
	BRNE	update
	CP	R31,R21
	BREQ	same1
update:
	STS     LWRD(previoustcb),R30	;store active task tcb
	STS     LWRD((previoustcb+1)),R31
	PUSH	R30			;yes
	PUSH	R31
	CALL	cmxtracker_in_task	;go inform tracker
	POP	R31
	POP	R30
	LDD	R18,Z+tcbstate_high	;get task state
same1:
 ENDIF
	LDI	R16,RUNNING		;show that task is now executing
	STD 	Z+tcbstate_high,R16	;store task new state
	ANDI	R18,READY	;now see if task should start or resume
	BREQ	resume_good	
	RJMP	task_ready	;task should start at beginning brace
resume_good:
	CLI	
	LDD	R28,Z+stk_save	;task is resuming, load saved stack address
	LDD	R29,Z+stk_save+1 
	LDD	R20,Z+system_stk_save	;task is resuming, load saved system stack address
	LDD	R21,Z+system_stk_save+1 
	OUT	0x3D,R20
	OUT	0x3E,R21
	SEI	
 IF SAVE_RAMPZ > 0
        LD      R16,Y+	;GET RAMPZ
        OUT     LOW(RAMPZ),R16
 ENDIF
	LD	R0,Y+	;restore registers
	LD	R1,Y+
	LD	R2,Y+
	LD	R3,Y+
	LD	R4,Y+
	LD	R5,Y+
	LD	R6,Y+
	LD	R7,Y+
	LD	R8,Y+
	LD	R9,Y+
	LD	R10,Y+
	LD	R11,Y+
	LD	R12,Y+
	LD	R13,Y+
	LD	R14,Y+
	LD	R15,Y+
	LD	R17,Y+
	LD	R18,Y+
	LD	R19,Y+
	LD	R20,Y+
	LD	R21,Y+
	LD	R22,Y+
	LD	R23,Y+
	LD	R24,Y+
	LD	R25,Y+
	LD	R26,Y+
	LD	R27,Y+
;	LD	R28,Y+	;do not restore Y
;	LD	R29,Y+
	LD	R30,Y+
	LD	R31,Y+
	CLI	;turn interrupts off
	LDS	R16,LWRD(cmx_flag1)	;get flags
	ANDI	R16,~(idle_flag | do_time_slice)	;reset these 2 flags
	STS	LWRD(cmx_flag1),R16
	ANDI	R16,(do_int_pipe | do_timer_tsk) ;test to see if bit(s) set
	BREQ	resume_good1	;no then go let task run
	SEI
	RJMP	sched_x		;yes, then process bits first
resume_good1:
	LDI	R16,H'00		
	STS	LWRD(int_count),R16	;set int count to 1, for using stack
	STS	LWRD(locked_out),R16	;set locked out to 1, critical region
        LD      R16,Y+	;GET SREG
        OUT     LOW(63),R16
	LD	R16,Y+
;	SEI	;enable interrupts
 	RET	;return to task

task_ready:
	LDD	R0,Z+task_addr	;it's location in ROM
	LDD	R1,Z+task_addr+1 
	LDD	R20,Z+system_stk_start	;task starting, load system stack start address
	LDD	R21,Z+system_stk_start+1 
	CLI	;turn interrupts off
	LDS	R16,LWRD(cmx_flag1)
	ANDI	R16,~(idle_flag | do_time_slice)
	STS	LWRD(cmx_flag1),R16
	ANDI	R16,(do_int_pipe | do_timer_tsk) ;test to see if bit(s) set
	BREQ	task_ready1	;no then go let task run
	LDI	R16,READY	;put task back to ready
	STD 	Z+tcbstate_high,R16	;store task new state
;No sense to do much with this task, because it wants to start at beginning address
	RJMP	sched_again	;yes, then process bits first
task_ready1:
	LDD	R28,Z+stk_start	;get task user stack start address
	LDD	R29,Z+stk_start+1 
	OUT	0x3D,R20
	OUT	0x3E,R21
	LDI	R16,H'00		
	STS	LWRD(int_count),R16	;set int count to 0
	STS	LWRD(locked_out),R16	;set locked out to 0
	MOV	R30,R0
	MOV	R31,R1
	SEI	;enable interrupts
	IJMP			;jump to task's beginning address

	RSEG	CODE(0)

K_OS_Intrp_Entry: 
; for devices with up to 16 bit PC (128K ROM), return PC size is 2 bytes	
; for devices with up to 22 bit PC (8 Meg ROM), return PC size is 3 bytes	
; This way, when interrupt issues a RETI, it will return to K_OS_Intrp_Exit
; and not the PC of interrupted code
	ST	-Y,R19	;save up 4 registers (6 for 22 bit PC)
	ST	-Y,R18	;2 are used for INTERRUPT return address, 2 for K_OS_Intrp_Exit address
	ST	-Y,R17	
	ST	-Y,R16
	LDS	R16,LWRD(cmx_flag1)	;we might not have to test for active?
	SBRS	R16,LOW(bit_cmx_active)
	RJMP	cxint_in1
	LDS	R16,LWRD(int_count)	;increment int_count (nested counter)
	INC	R16	
	STS	LWRD(int_count),R16
cxint_in1:
	LDI	R16,LOW(K_OS_Intrp_Exit/2)	;place K_OS_Intrp_Exit address on stack, so 
	LDI	R17,((K_OS_Intrp_Exit/2) >> 8)	;interrupt returns to K_OS_Intrp_Exit
	POP	R18	;get return address of interrupt that called K_OS_Intrp_Entry
	POP	R19
	PUSH	R16	
	PUSH	R17	;push K_OS_Intrp_Exit on system stack, so interrupt returns to here
	PUSH	R19	;push original return back on now
	PUSH	R18
	LD	R16,Y+	;restore registers
	LD	R17,Y+
	LD	R18,Y+
	LD	R19,Y+
	RET		;return to caller
	
K_OS_Intrp_Exit: 		;when interrupt issues the RETI, it will now come here
	ST	-Y,R16	;save reg 16
        IN      R16,LOW(63)	;get SREG
        ST      -Y,R16	;save that as well
	CLI	;turn interrupts off
	LDS	R16,LWRD(cmx_flag1)	;we might not have to test for active?
	SBRS	R16,LOW(bit_cmx_active)
	RJMP	cxint_ex1
	LDS	R16,LWRD(int_count)	;get nested int_count
	DEC	R16			;decrement it
	STS	LWRD(int_count),R16	;write it back
	BRNE	cxint_ex1	;yes, exit. Not zero
	LDS	R16,LWRD(locked_out)
	CPI	R16,0		;see if we are locked out
	BRNE	cxint_ex1	;yes, exit
	LDS	R16,LWRD(cmx_flag1)	;we might not have to test for active?
	ANDI	R16,(do_int_pipe | preempted | do_timer_tsk | do_time_slice | do_coop_sched)
	BREQ	cxint_ex1	;yes, exit
	LDI	R16,H'01		
	STS	LWRD(locked_out),R16	;set locked out to 1, critical region
	SEI
	JMP	sched_x		;otherwise go save task context.
cxint_ex1:
        LD      R16,Y+	;GET SREG
        OUT     LOW(63),R16	;restore it
	LD	R16,Y+	;restore reg 16
	RET		;return to where interrupt had interrupted

K_OS_Disable_Interrupts: 
	CLI	;disable interrupts
	RET

K_OS_Enable_Interrupts: 
	SEI	;enable interrupts
	RET

K_OS_Save_Interrupts: 
	ST	-Y,R16		;save reg 16
        IN      R16,LOW(63)	;get SREG
	CLI			;turn interrupts off
	STS	LWRD(ie_holder),R16	;save SREG
	LD	R16,Y+		;restore r16
	RET

K_OS_Restore_Interrupts: 
	ST	-Y,R16		;save reg 16
	LDS	R16,LWRD(ie_holder)	;get saved SREG
        OUT     LOW(63),R16	;put back to original value
	LD	R16,Y+		;restore reg 16
	RET

	END

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -