📄 rtoslite.asm
字号:
; RTOSLite - Lite RTOS Version
;
; This Code Loads in "App.asm" and executes it starting at
; "Application".
;
; Each Task is set in an individual Register Bank. The
; Registers are defined as follows:
;
; Register Function
; R0 Message Pointer/Index/Task Address/GP Register
; R1 RTOS Request Number/Index/Task Address/GP Register
; R2 GP Task Register/Task Address
; R3 Task Block Information
; R4 Low Byte of Return Address
; R5 High Byte of Return Address
; R6 Saved Accumulator
; R7 Saved PSW
;
; NOTE:
;
; 1. The Stack Pointer is set by the RTOS to address of "R3"
; 2. No subroutines can be called from within the Tasks
; 3. R2 should be used for Information that Doesn't Change
; 4. Currently Executing Task Recorded in RS0/RS1 of PSW
; 5. The Task Block Bank Register is defined as:
; Bit Function
; 5 0
; 000000 Task Can Execute
; 1nn000 Sent Message to Task "nn", Waiting for Ack
; 001xxx Waiting for a Message
; 01iiii Waiting for Interrupt Number
; 0FFh No Task Loaded for Register Bank
; 6. Task 3 is the always Available Task
;
;
; The following Operations have been included (as Macros which
; may call the mainline):
;
; Function Input Output Data Comments
;
; SendMsg Acc = Ptr to Msg in Scratchpad Block until the Message is
; Acknowledged
;
; WaitMsg Wait Until A Task has
; a Message for Current
;
; ReadMsg Task # Acc = Pointer to Msg Return Non-Zero if
; Acc = 0 if No Msg Message is being sent
; to the Current Task
; From the Task
;
; AckMsg Task # Acknowledge the Message
; from the Specific Task
;
; StartTask R1/R2 = Task Addr Start the Specified Task
; Acc = Task # (with the address)
; Acc = -1 if Nothing Available
;
; EndTask Have the Task End itself
;
; NextTask Jump to the Next Executable
; Task
;
; WaitInt Int # Wait for the Given Interrupt
;
; GetSem Semaphore # Wait for the Semaphore to
; become Available
;
; RelSem Semaphore # Release the Semaphore
;
; Myke Predko
; 98.03.01
;
; Hardware Notes:
; Operation of the RTOS is dependant on the Application
; Variable Declarations
; 020h - the Semaphore Byte
; RTOS Function Macros
MACRO NextTask ; Let the Next Task Execute
acall _RTOSNextTask
ENDMAC
MACRO EndTask ; End the Current Task
mov R3,#0FFh ; Set Task Block that it has Ended
acall _RTOSNextTask
ENDMAC
MACRO StartTask Task ; Start the New Task
mov R0,#(Task AND 255)
mov R1,#(Task SHR 8)
acall _RTOSStartTask ; Task Number in Acc (or -1)
ENDMAC
MACRO WaitInt(Number) ; Wait for the Specific Interrupt Number
mov R3,#(%00010000 OR (1 SHL Number)) ; Wait for Specified Interrupt
acall _RTOSNextTask ; Now, Start Waiting for the Other Tasks
ENDMAC
MACRO RelSem(Number) ; Release the Semaphore Number
setb Number ; Just Set the Semaphone Number
ENDMAC
MACRO GetSem(Number) ; Get the Semaphore
@_RTOSGetSem: ; Loop Back Here for Each Semaphore
jnb Number,@_RTOSGetSemGot ; Semaphore Gotten
acall _RTOSNextTask ; Wait for the Next Task
ajmp @_RTOSGetSem ; Try to get the Semaphore Again
@_RTOSGetSemGot: ; Have the Semaphore
ENDMAC
MACRO AckMsg(Task) ; Acknowledge the Message from Task #
mov ((Task * 8) + 3),#0 ; Tell the Task to Stop Waiting
ENDMAC
MACRO ReadMsg(Task) ; Read the Message from the Task
mov R0,#((Task SHL 3) + 3) ; Make Sure the Correct Address
acall _RTOSReadMsg
ENDMAC
MACRO SendMsg(Task,Ptr) ; Send the Message Pointed to
mov R3,#(%00100000 OR (Task SHL 3)) ; Block the Task
mov R1,#((Task SHL 3) + 3)
mov R0,#Ptr
acall _RTOSSendMsg
ENDMAC
MACRO WaitMsg ; Wait for the Message to be Send
mov R3,#%1000 ; Make the Task Blocking
acall _RTOSWaitMsg
ENDMAC
; Mainline
org 0 ; Execution Starts Here
ajmp _RTOSMain ; Jump to the RTOS Initialization Code
org 0003h ; _Int0 Interrupt
clr IE.7 ; Disable Global Interrupts
push ACC ; Save the Accumulator
mov A,#0FEh ; Have Interrupt 0
ajmp _RTOSInt ; Handle the Interrupt
org 000Bh ; Timer0 Interrupt
clr IE.7 ; Disable Global Interrupts
push ACC ; Save the Accumulator
mov A,#0FDh ; Have Timer 0 Interrupt
ajmp _RTOSInt ; Handle the Interrupt
org 0013h ; _Int1 Interrupt
clr IE.7 ; Disable Global Interrupts
push ACC ; Save the Accumulator
mov A,#0FBh ; Have Interrupt 1
ajmp _RTOSInt ; Handle the Interrupt
org 001Bh ; Timer1 Interrupt
clr IE.7 ; Disable Global Interrupts
push ACC ; Save the Accumulator
mov A,#0F7h ; Have Timer 1 Interrupt
_RTOSInt: ; Handle the Interrupt Reqests
anl IE,A ; Disable the Requested Interrupt and Global Ints
push PSW ; Save the Task's PSW
cpl A
orl A,#%00010000 ; In "A", Have the Expected Interrupt Wait Value
xrl A,3 ; Now, Is Task 0 Waiting for This?
jnz _RTOSI1 ; No, Check Task 1
xch A,3 ; Mark that the Task Can Now Run
_RTOSI1: ; Restore the Accumulator
xrl A,3
xrl A,00Bh ; Check the Next Task
jnz _RTOSI2 ; It's not, Check Task 2
xch A,00Bh
_RTOSI2: ; Restore the Accumulator
xrl A,00Bh
xrl A,013h
jnz _RTOSDoNextTask ; It's not, Jump to the Next Task Code
xch A,013h ; It is, Enable the Task
ajmp _RTOSDoNextTask
_RTOSStartTask: ; Start the Specified Task
push ACC ; Save the Context Information
push PSW
mov A,3 ; Look for a Task that's Available
cjne A,#0FFh,_RTOSStartTask1 ; If Task0 Not Available, Check Task1
mov 4,R0 ; Save the Task Starting Address
mov 5,R1
mov R6,#0
clr A ; Going to Have Task 0
ajmp _RTOSStartTaskDo ; Have the New Task
_RTOSStartTask1: ; Check to See if Task1 Is Available
mov A,00Bh
cjne A,#0FFh,_RTOSStartTask2 ; If Not Available, Check Task 2
mov 00Ch,R0 ; Save the Task Starting Address
mov 00Dh,R1
mov R6,#1
mov A,#%00001000
ajmp _RTOSStartTaskDo ; Now, Start the New Task Executing
_RTOSStartTask2: ; Check Task 2
mov A,013h
cjne A,#0FFh,_RTOSStartTaskNo ; No Task Available
mov 014h,R0 ; Save the Task Starting Address
mov 015h,R1
mov R6,#2
mov A,#%00010000
_RTOSStartTaskDo: ; Have the Task to Start up
mov PSW,A
mov R3,#0 ; Indicate that the Task Can Execute
add A,#5 ; Convert the Value into a Stack Pointer
mov SP,A
ret ; Start the Task Executing
_RTOSStartTaskNo: ; No Task is Available
mov R6,#0FFh ; Return -1
ajmp _RTOSExecuteTask ; Now, Start up the Task
_RTOSNextTask: ; Jump to the Next Active Task
push ACC ; Save the Task Registers
push PSW
_RTOSDoNextTask: ; Now, Find the Next Task
mov A,PSW ; Which Task is Active?
add A,#%00001000 ; Just Increment the Bank Register
anl A,#%00011000 ; Make Sure Task isn't > %00011000
mov PSW,A
_RTOSDoNextTaskNextCheck: ; Check the Task to See if it can Execute
cjne R3,#0,_RTOSDoNextTask ; If Task Information Block == 0, then Execute it
_RTOSExecuteTask: ; Now, the Task can Start Executing
mov A,PSW ; Get the Correct Stack Pointer
anl A,#%00011000 ; Get Rid of Extra Bits
add A,#7 ; At the End of the Register Bank
mov SP,A
pop PSW ; Restore the PSW
pop ACC
reti ; Return Where Program Stopped
_RTOSReadMsg: ; Read the Message from the Task in A
mov A,@R0 ; Get the Message Number
xrl A,PSW ; Do we Have a Match?
anl A,#%00111000 ; Is It Waiting for This Task?
xrl A,#%00100000
jz _RTOSReadMsgHave ; Yes, Have the Message
clr A ; Else, the Message isn't There
ret
_RTOSReadMsgHave: ; Have the Message, Return It
dec R0 ; Now, Point to the Actual Message
dec R0
dec R0
mov A,@R0 ; R0 is Pointing to the Message Pointer of the Task
ret
_RTOSSendMsg: ; Send the Message to the Task
cjne @R1,#%1000,_RTOSNextTask ; If the Task ISN'T Waiting for the Message, Jump On
mov @R1,#0 ; Yes, Free Up the Task
ajmp _RTOSNextTask ; Jump to the Next Active Task
_RTOSWaitMsg: ; Waiting for a Message, See if Something There First
mov A,3 ; See if Anything is Waiting to Send to This Task
xrl A,PSW
anl A,#%00111000
xrl A,#%00100000
jz _RTOSWaitMsgHave ; Something is Sending to the Task
mov A,00Bh
xrl A,PSW
anl A,#%00111000
xrl A,#%00100000
jz _RTOSWaitMsgHave
mov A,013h
xrl A,PSW
anl A,#%00111000
xrl A,#%00100000
jnz _RTOSNextTask
_RTOSWaitMsgHave: ; Have the Message, Can Continue to Execute
mov R3,#0 ; Can Start Executing Again
ajmp _RTOSNextTask ; See what is to Execute Next
_RTOSMain: ; RTOS Initialization Code
mov 020h,#00Fh ; Clear the Semaphores (Set them)
mov 003h,#0FFh ; Mark the Tasks as Not Available
mov 00Bh,#0FFh
mov 013h,#0FFh
mov 01Bh,#000h ; Setup Task 3 as "_AlwaysTask"
mov SP,#01Dh ; Setup the Stack to Start the Task
setb PSW.3 ; Make Sure the Accumulator Knows
setb PSW.4 ; Where to get the Regiseters from
clr A ; Clear the Accumulator
mov 01Ch,#(_AlwaysTask AND 255)
mov 01Dh,#(_AlwaysTask SHR 8)
ret ; Jump to the _AlwaysTask
_AlwaysTask: ; The Always Available Task
StartTask Application ; Start the Application Task
_AlwaysTaskLoop: ; Loop Here Forever
clr IE.7 ; Disable Global Interrupts
NextTask ; Look at the Next Task
setb IE.7 ; Allows Interrupts to Happen
ajmp _AlwaysTaskLoop ; Loop Around (with Interrupts Enabled)
; #### - Put in Test Application Code Here
Application: ; Simple Test Application
StartTask App2 ; Start a Second Task
EndTask ; End this Task
App2: ; Second Task
mov CKCON,#%00001000 ; Use Internal /4 Clock for Timer0
mov TMOD,#%00000001 ; Timer0 - Uses Internal Clock
; - Run in Mode 1
mov TCON,#%00010000 ; Start Timer0 running
mov 021h,#0 ; Use Address 21 as the Data Byte
StartTask App3 ; Start the Third Application
mov 022h,#15 ; Set the Counter for a One Second Loop
Application_Loop: ; Loop Around Here
setb IE.1 ; Enable the Timer 0 Interrupt
WaitInt(1) ; Wait for the Interrupt
djnz 022h,Application_Loop ; Wait for the Counter to Count to 1 Second
SendMsg(2,021h)
inc 021h ; Increment the Output Value
mov 022h,#15 ; Reload the Counter
ajmp Application_Loop
App3: ; Wait for Messages from App2
WaitMsg ; Wait for a Message
ReadMsg(1) ; Read the Message from Task 0
mov R0,A ; Read and Output the Message
mov A,@R0
cpl A ; Invert the Data Before Displaying
mov P1,A
AckMsg(1) ; Acknowledge the Message
ajmp App3
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -