Wednesday, June 10, 2009

PIC18F452 İLE GERÇEK ZAMANLI İŞLETİM SİSTEMİ (RTOS)



Gömülü sistemlerde en kullanışlı uygulama ortamlarından biri de Gerçek Zamanlı İşletim Sistemleridir. Real Time Operating System – Kısaca RTOS). Uygun bir yaklaşımla kullanıldığında uygulamayı daha yalın hale getirir ve bir çok görevin de uygulama içinde daha iyi yönetilmesini ve olası hataların daha az yapılması sağlar. 
PIC mikro denetleyiciler için bu PIC18 ailesi çıkana kadar böyle bir seçenek yoktu. PIC18 ile birlikte bootloader yanında RTOS uygulamaları için gerekli altyapı sağlanmaktadır.
RTOS, bir çok program görevlerini (threads) yürüten, bunlar arasındaki önceliklendirmeyi ve ilişkileri yöneten bir uygulamadır.
Bizim projemizde ledlerin farklı iki görevli program tarafından sıra ile kendi belirledikleri şekilde yakılmasını görüyoruz.

RTOS Gerçekleştirilmiş Hali




Basit RTOS Devre Şeması


RTOS Assembly Programı


TaskStart macro Address, Priority, Size
  bcf     INTCON, GIE             ;  Disable Interrupts During RTOS Request Operation
  movlw   0x00F
  iorwf   0x060, f, 0             ;  Mark in RTOS there is a Command
  movlw   Size                    ;  Save the Number of File Registers
  movwf   FSR1L, 0        
  movlw   Priority << 4           ;  Save the Application's Priority
  movwf   FSR0L, 0
  push                     ;  Make Sure Call Address Not Taken
  movlw   Address & 0x0FF  ;  Save its Starting Address
  movwf   TOSL, 0
  movlw   (Address & 0x0FF00) >> 8
  movwf   TOSH, 0
  movlw   (Address & 0x0FF0000) >> 16
  movwf   TOSU, 0
  movlw   0
  call    _RTOS
  pop                      ;  Pop the Address Passed
 endm
;
;  Next Task        Skip Execution to the Next Task   None
TaskNext macro
  bcf     INTCON, GIE             ;  Disable Interrupts During RTOS Request Operation
  call    _RTOS                   ;  Just Call the RTOS
 endm
;
;  Wait for Interrupt      Wait for the Specified            None
;                   Interrupt Request.  When
;                   Received, Interrupt "F" and  "E" Bits are Reset
IntWait macro Interrupt
  bcf     INTCON, GIE             ;  Disable Interrupts During RTOS Request Operation
  movf    0x060, w, 0             ;  Read in the Flag Register
  andlw   0x030                   ;  Clear Everything But Priority
  iorlw   Interrupt        ;  Note the Interrupt Number
  movwf   0x060, 0
  call    _RTOS
 endm
;
;  Send Message            Task Number                None
;                   2 Byte Message in FSR0L/FSR1L
MsgSend macro TaskNumber   ;  Assume FSR0L/FSR1L already Set up
  bcf     INTCON, GIE             ;  Disable Interrupts During RTOS Request Operation
  movf    0x060, w, 0             ;  Read in the Flag Register
  andlw   0x030
  iorlw   0x040
  iorwf   TaskNumber, w, 0 ;  Note, Task Number is a Variable
  movwf   0x060, 0
  call    _RTOS
 endm
;
;  Wait Message            None                       First 2 Byte Message
;                                              in FSR0L/FSR1L
MsgWait macro
  bcf     INTCON, GIE             ;  Disable Interrupts During RTOS Request Operation
  bcf     0x060, 6, 0             ;  Mark Waiting for Message
  call    _RTOS
 endm
;
;  Read Message            Task Number                Carry Set, no Message being
;                                              Sent
;                   Carry Reset, Message Sent and Returned in FSR0L-FSR1L
MsgRead macro TaskNumber
  bcf     INTCON, GIE             ;  Disable Interrupts During RTOS Request Operation
  movlw   0x00F
  iorwf   0x060, f, 0             ;  Set the Appropriate Message Number
  movlw   0x010
  iorwf   TaskNumber, w, 0
  call    _RTOS
 endm
;
;  Ack Message             Task Number                Carry Set, no Message Waiting
;                                              Carry Reset, Message Acked
MsgAck macro TaskNumber
  bcf     INTCON, GIE             ;  Disable Interrupts During RTOS Request Operation
  movlw   0x00F
  iorwf   0x060, f, 0             ;  Note to RTOS that it is a Command
  movlw   0x020
  iorwf   TaskNumber, w, 0 ;  Specify the Task Number
  call    _RTOS
 endm
;
;  Interrupt Numbers:
;   #   Function    Register
;   0 - TMR1    PIR1
;   1 - TMR2     PIR1
;   2 - CCP1     PIR1
;   3 - SSP      PIR1
;   4 - TX       PIR1
;   5 - RC       PIR1
;   6 - AD       PIR1
;   7 - PSP      PIR1
;   8 - CCP2     PIR2
;   9 - TMR3     PIR2
;  10 - LVD      PIR2
;  11 - BCL      PIR2
;  12 - RB       INTCON
;  13 - INT0     INTCON
;  14 - TMR0     INTCON - Note "E" Flag is NOT Reset
;  15 - SPECIAL Indicator to RTOS that WREG has the RTOS Function Number
;  Task Information Block Definition:
 CBLOCK 0
TIB                        ;  Task Information Block
_wreg, _status, _bsr              ;  Execution Context Registers
_pclath, _pclatu           ;  Jump Context Registers
_tablptrl, _tablptrh, tablat      ;  Table Access Context Registers
_prodl, _prodh                    ;  Multiplication Product
_fsr0:2                           ;  FSR0
_fsr1:2                           ;  FSR1
_tos_1:3                   ;  First Top of Stack
_tos_2:3                   ;  Second Top of Stack
_tos_3:3                   ;  Third Top of Stack
 ENDC
;
;  One Task Information Block is placed for each Task with the Task's
;   File Registers following them. 
;
;  The "Task Flag Register" is Defined as:
;  Bits     Function
;  7-6      Execution Type
;            11 - Active, Can Run
;            10 - Waiting to Receive Message
;            01 - Sending Message/Waiting for Ack
;            00 - Waiting for Interrupt
;  5-4      Task Priority
;            11 - Highest
;             :
;            00 - Lowest
;  3-0       Send Task Address/Interrupt Number Delay
;
;
;  Hardware Notes:
;   The PIC18Cxx is Running at 4 MHz.
;   Reset is tied directly to Vcc and PWRT is Enabled.
;   TMR0 is running and Interrupts the PICMicro every 32.768 usecs
;   I/O Ports and other resources are defined by the Applications
;
;
  LIST R=DEC, F=INHX32
  INCLUDE "p18f452.inc"


;  Register Usage
 CBLOCK 0x00C                   ;  Start Registers at End of the Values
Dlay:2
 ENDC

;  Macros

PAGE
 ;__CONFIG _CONFIG0, _CP_OFF_0
 ;__CONFIG _CONFIG1, _OSCS_OFF_1 & _XT_OSC_1
 ;__CONFIG _CONFIG2, _PWRT_ON_2 & _BOR_ON_2 & _BORV_42_2
; __CONFIG _CONFIG3, _WDT_OFF_3
; __CONFIG _CONFIG5, _CCP2MX_OFF_5    
; __CONFIG _CONFIG6, _STVR_OFF_6

    __CONFIG    _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L & _CP3_OFF_5L ; all protection off
    __CONFIG    _CONFIG1H, _OSCS_ON_1H & _XT_OSC_1H ; External Clock on OSC1 & OSC2
    __CONFIG    _CONFIG2L, _BOR_ON_2L & _BORV_20_2L & _PWRT_ON_2L ; Brown out reset on at 2.0V, no power-up timer
    __CONFIG    _CONFIG2H, _WDT_OFF_2H & _WDTPS_128_2H ; watchdog off, postscaler count to 128
    __CONFIG    _CONFIG3H, _CCP2MX_OFF_3H ; CCP2 pin Mux enabled. What is this?
    __CONFIG    _CONFIG4L, _STVR_OFF_4L ;& _LVP_ON_4L & _DEBUG_OFF_4L ; Stack under/overflow reset on, LVP on, debug off


                                ;  Note that the WatchDog Timer is OFF
;  Demo Code, Loop Forever Toggling PA0 (Flashing the LED)

  org     0                ;  Reset Vector

  clrf    TMR0L, 0         ;  Reset TMR0
  movlw   (1 << TMR0ON) + (1 << T08BIT) + 5
  movwf   T0CON                   ;  Start T0CON executing

  bra     _ATSetup               

 org      8
_RTOS                      ;  Treat RTOS as an address Vector
  movff   WREG, 0x061             ;  Start Saving the Context Registers
  movff   STATUS, 0x062
  movlw   0x062
  movwf   FSR2L, 0         ;  Setup the Pointer to the FSR Register
  clrf    FSR2H, 0
  movff   BSR, PREINC2            ;  Save the Last Context Register
  movff   PCLATH, PREINC2
  movff   PCLATU, PREINC2
  movff   TBLPTRL, PREINC2
  movff   TBLPTRH, PREINC2
  movff   TABLAT, PREINC2
  movff   PRODL, PREINC2
  movff   PRODH, PREINC2
  movff   FSR0L, PREINC2
  movff   FSR0H, PREINC2
  movff   FSR1L, PREINC2
  movff   FSR1H, PREINC2
  movlw   3                ;  Save the top 3 Stack Elements
_RTOS_SaveStack
  movff   TOSL, PREINC2           ;  Save the Return Address
  movff   TOSH, PREINC2
  movff   TOSU, PREINC2
  pop
  decfsz  WREG, f, 0
   bra    _RTOS_SaveStack

;  Save the Registers in Memory
  movlw   0x078                   ;  Find the Active Task
  movwf   FSR0L, 0
  clrf    FSR0H, 0
  movlw   0x080
  movwf   FSR1L, 0
  clrf    FSR1H, 0
_RTOS_SaveFind
  btfsc   INDF0, 7         ;  Bit 7 Set for the Task?
   bra    _RTOS_SaveFound
  movf    POSTINC0, 0             ;  Get the Value to Add to FSR1L for the Offset
  addwf   FSR1L, f, 0
  btfsc   STATUS, C, 0
   incf   FSR1H, f, 0
  bra     _RTOS_SaveFind
_RTOS_SaveFound                   ;  FSR1 is Pointing to the Task Memory
  movf    INDF0, w, 0             ;  Get the Count
  movwf   FSR2L, 0
  movlw   0x060                   ;  Save the Task Information
  movwf   FSR0L, 0
  clrf    FSR0H, 0
  movlw   0x018                   ;  Save all 0x018 Context Register Bytes
_RTOS_SaveContext
  movff   POSTINC0, POSTINC1      ;  Move the Value Right In
  decfsz  WREG, f, 0
   bra    _RTOS_SaveContext
  movlw   0x098                   ;  Get the Byte Count to Save
  subwf   FSR2L, w, 0
  btfsc   STATUS, Z, 0
   bra    _RTOS_SaveDone
  clrf    FSR0L, 0         ;  Start at Beginning
  clrf    FSR0H, 0
_RTOS_SaveRegister
  movff   POSTINC0, POSTINC1
  decfsz  WREG, f, 0
   bra    _RTOS_SaveRegister
_RTOS_SaveDone                    ;  Task Information Saved

;  Check the Interrupt Registers for Requests

  clrf    FSR0L, 0         ;  Clear the Offset Counter
  movlw   8                ;  Start with 8 Bits
  movwf   FSR0H, 0
  movf    PIR1, w, 0              ;  Start with PIR1 (Bits 0 - 7)
  movwf   FSR1L, 0
  btfss   STATUS, Z, 0
   bra    _RTOS_HaveInt
  movlw   8                ;  PIR2 (Bits 8 - 11)
  movwf   FSR0L, 0
  movlw   4
  movwf   FSR0H, 0
  movf    PIR2, w, 0
  andlw   0x00F                   ;  Only 4 Bits
  movwf   FSR1L, 0
  btfss   STATUS, Z, 0
   bra    _RTOS_HaveInt
  bsf     FSR0L, 2, 0             ;  INTCON (Bits 12 to 14)
  decf    FSR0H, f, 0
  movf    INTCON, w, 0
  andlw   0x007                   ;  Only 3 Bits
  movwf   FSR1L, 0
  btfsc   STATUS, Z, 0
   bra    _RTOS_Action
_RTOS_HaveInt              ;  Figure Out the Interrupt Number
  incf    FSR0L, f, 0             ;  Increment the
  rrcf    FSR1L, f, 0             ;  Shift Down the Bit
  btfss   STATUS, C, 0            ;  Have the Bit? 
   bra    _RTOS_HaveInt
  decf    FSR0L, f, 0             ;  Correct Number In FSR0L

  movff   FSR0L, FSR0H            ;  Get the Correct Bit
  movlw   PIR1 & 0x0FF
  movwf   FSR1L, 0
  movlw   PIE1 & 0x0FF
  movwf   FSR2L, 0
  btfss   FSR0H, 3         ;  Which Register? 
   bra    _RTOS_ClearInt
  bcf     FSR0H, 3         ;  Look for PIR2
  movlw   PIR2 & 0x0FF
  movwf   FSR1L, 0
  movlw   PIE2 & 0x0FF
  movwf   FSR2L, 0
  btfss   FSR0H, 2
   bra    _RTOS_ClearInt
  bcf     FSR0H, 2         ;  Have INTCON
  movlw   INTCON & 0x0FF
  movwf   FSR1L, 0
  movwf   FSR2L, 0
_RTOS_ClearInt                    ;  Find Bit to Clear
  movlw   0x00F
  movwf   FSR1H, 0
  movwf   FSR2H, 0
  movlw   0x0FE
  movf    FSR0H, f, 0             ;  Set Zero Flag if Bit Number is Zero
  btfsc   STATUS, Z, 0
   bra    $ + (2 * 4)
  rlncf   WREG, f, 0
  decfsz  FSR0H, f, 0
   bra    $ - (2 * 2)
  movff   FSR0L, FSR0H            ;  Save the Bit Number
  andwf   INDF1, f, 0             ;  Clear the "F" Bit
  movwf   FSR0L, 0         ;  Save Mask for "E" Bit
  movlw   14               ;  Do we Have a TMR0?
  xorwf   FSR0H, w, 0            
  btfsc   STATUS, Z, 0
   bra    _RTOS_ClearDone
  movlw   0x00C                   ;  Is this an INTCON Value? 
  andwf   FSR0H, w, 0
  xorlw   0x00C
  btfss   STATUS, Z, 0
   bra    _RTOS_ClearDo
  rlncf   FSR0L, f, 0             ;  INTCON - Shift the Mask Up by 3 to Reset
  rlncf   FSR0L, f, 0            
  rlncf   FSR0L, f, 0            
_RTOS_ClearDo
  movf    FSR0L, w, 0
  andwf   INDF2, f, 0             ;  Clear the "E" Bits
_RTOS_ClearDone                   ;  The Interrupt Bits are Cleared

  movlw   0x078                   ;  Interrupt Number if FSR0H
  movwf   FSR1L, 0
  clrf    FSR1H, 0
  movlw   0x080                   ;  Look at the Flag Register
  movwf   FSR2L, 0
  clrf    FSR2H, 0 
_RTOS_IntResetLoop
  movf    FSR0H, w, 0             ;  Does the Interrupt Match the Waiting? 
  xorwf   INDF2, w, 0
  andlw   0x00F
  btfss   STATUS, Z, 0
   bra    _RTOS_IntResetSkip
  movlw   0x030                   ;  Reset the Check Value
  andwf   INDF2, w, 0
  iorlw   0x0C0                   ;  Mark that it is Active
  movwf   INDF2, 0
_RTOS_IntResetSkip
  movf    POSTINC1, w, 0   ;  Get the Increment Value
  andlw   0x07F                   ;  Make Sure Top Bit is Reset
  addwf   FSR2L, f, 0             ;  Add to the Offset
  btfsc   STATUS, Z, 0
   incf   FSR2H, f, 0
  movf    INDF1, f, 0
  btfsc   STATUS, Z
   bra    $ + (2 * 3)             ;  Zero, Gone through the List
  btfss   INDF0, 7, 0             ;  Value == 0x080 (Past End?)
   bra    _RTOS_IntResetLoop

;  Now, Look through for Action in the Operation
_RTOS_Action

  movlw   0x078                   ;  Look for Tasks Waiting for Action
  movwf   FSR0L, 0
  clrf    FSR0H, 0
  movlw   0x080                   ;  Keep Track of the TASK Address
  movwf   FSR1L, 0
  clrf    FSR1H, 0 
_RTOS_ActionLoop
  movf    INDF1, w, 0
  andlw   0x00F                   ;  Do we Have an "Action" Command? 
  xorlw   0x00F
  btfss   STATUS, Z, 0
   bra    _RTOS_ActionDone ;  No, Skip Over
  movlw   1                ;  Check the "w" Register for the Command
  btfss   PLUSW1, 5, 0
   bra    _RTOS_ActionNotAck

_RTOS_ActionAck                   ;  Look for Task Sending to Current
  movf    INDF1, w, 0             ;  Current Task can Execute Afterward no matter what
  andlw   0x0F0                   ;  Clear out the Task Number
  iorlw   0x0C0                   ;  Indicate that it is Active
  movwf   INDF1, 0
  movff   FSR1L, TBLPTRL   ;  Save the contents of FSR1
  movff   FSR1H, TBLPTRH
  movlw   _wreg                   ;  Get the Task Number
  movf    PLUSW1, w, 0           
  andlw   0x0FF ^ (1 << 5)
  movwf   PRODH, 0
  movlw   8
  subwf   PRODH, w, 0             ;  Do we Have a Problem? 
  btfsc   STATUS, C
   bra    _RTOS_ActionAckError    ;  Yes, Task Number is > 7, or Other Bits Set
  movlw   0x078                   ;  Point to the Task Table
  movwf   FSR1L, 0
  clrf    FSR1H, 0
  movlw   0x080                   ;  Point to the First Task
  movwf   FSR2L, 0
  clrf    FSR2H, 0
  movlw   0x078                   ;  Get the Task Number Sending
  subwf   FSR0L, w, 0
  movwf   PRODL, 0         ;  Use "PRODL" as a Temporary Register
  movwf   TABLAT, 0        ;  Use "TABLAT" as the Task Counter
_RTOS_ActionAckLoop        ;  Loop Here Until Task Found
  movf    TABLAT, f, 0            ;  Is "PRODL" equal to Zero? 
  btfsc   STATUS, Z, 0
   bra    _RTOS_ActionAckLoopEnd
  movf    POSTINC1, w, 0   ;  Add to the FSR2 Offset
  btfsc   STATUS, Z, 0
   bra    _RTOS_ActionAckError    ;  Error - If Zero, then not Loaded Task
  decf    TABLAT, f, 0
  btfsc   STATUS, Z, 0
   bra    _RTOS_ActionAckLoopEnd
  andlw   0x07F                   ;  Clear Bit 8 if active
  addwf   FSR2L, f, 0
  btfsc   STATUS, C, 0
   incf   FSR2H, f, 0
  bra     _RTOS_ActionAckLoop
_RTOS_ActionAckLoopEnd            ;  Have the Task that is Finished
  movlw   0x078
  subwf   FSR0L, w, 0
  movwf   PRODH
  movlw   _wreg
  movf    PLUSW2, w, 0
  xorwf   PRODH, w, 0
  andlw   0x00F
  btfss   STATUS, Z, 0
   bra    _RTOS_ActionAckError    ;  Doesn't Equal, A problem
  movff   TBLPTRL, FSR1L   ;  Restore FSR1
  movff   TBLPTRH, FSR1H
  movf    INDF2, w, 0
  andlw   0x030
  iorlw   0x0C0
  movwf   INDF2, 0         ;  Indicate to Sender it can Execute
  movlw   _status          ;  Indicate Operation Executed Correctly
  bcf     PLUSW1, C, 0           
  bra     _RTOS_ActionDone
_RTOS_ActionAckError              ;  Set Carry Flag if there is a Problem
  movff   TBLPTRL, FSR1L   ;  Restore FSR1
  movff   TBLPTRH, FSR1H
  movlw   _status
  bsf     PLUSW1, C, 0            ;  Task STATUS is two from the Start
  bra     _RTOS_ActionDone

_RTOS_ActionNotAck
  btfss   PLUSW1, 4, 0
   bra    _RTOS_ActionNewTask

_RTOS_ActionRead
  movf    INDF1, w, 0             ;  Current Task can Execute Afterward no matter what
  andlw   0x0F0                   ;  Clear out the Task Number
  iorlw   0x0C0                   ;  Indicate that it is Active
  movwf   INDF1, 0
  movff   FSR1L, TBLPTRL   ;  Save the contents of FSR1
  movff   FSR1H, TBLPTRH
  movlw   _wreg                   ;  Get the "WREG" Contents
  movf    PLUSW1, w, 0            ;  Save the Task Number
  andlw   0x0FF ^ (1 << 4)
  movwf   PRODH, 0
  movlw   8
  subwf   PRODH, w, 0             ;  Do we Have a Problem? 
  btfsc   STATUS, C
   bra    _RTOS_ActionReadError   ;  Yes, Task Number is > 7, or Other Bits Set
  movlw   0x078                   ;  Point to the Task Table
  movwf   FSR1L, 0
  clrf    FSR1H, 0
  movlw   0x080                   ;  Point to the First Task
  movwf   FSR2L, 0
  clrf    FSR2H, 0
_RTOS_ActionReadLoop              ;  Find the Specified Task Number
  movf    PRODH, f, 0
  btfsc   STATUS, Z, 0
   bra    _RTOS_ActionReadFound
  movf    POSTINC1, w, 0   ;  Get Offset Into Register Memory
  addwf   FSR2L, f, 0
  btfsc   STATUS, C, 0
   incf   FSR2H, f, 0
  decf    PRODH, f, 0
  bra     _RTOS_ActionReadLoop
_RTOS_ActionReadFound             ;  At the Corect Offset
  movf    INDF2, w, 0             ;  Is it Sending to this Task? 
  andlw   0x0C0
  xorlw   0x040
  btfss   STATUS, Z, 0
   bra    _RTOS_ActionReadError
  movlw   0x078
  subwf   FSR0L, w, 0
  xorwf   INDF2, w, 0
  andlw  0x00F
  btfss   STATUS, Z, 0
   bra    _RTOS_ActionReadError
  movff   TBLPTRL, FSR1L   ;  Save the contents of FSR1
  movff   TBLPTRH, FSR1H
  movlw   _fsr0                   ;  Transfer FSR0L Byte
  movff   PLUSW2, PLUSW1
  movlw   _fsr1
  movff   PLUSW2, PLUSW1
  movlw   _status          ;  Indicate Operation Executed Correctly
  bcf     PLUSW1, C, 0           
  bra     _RTOS_ActionDone
_RTOS_ActionReadError             ;  Set Carry Flag if there is a Problem
  movff   TBLPTRL, FSR1L   ;  Restore FSR1
  movff   TBLPTRH, FSR1H
  movlw   _status
  bsf     PLUSW1, C, 0            ;  Task STATUS is two from the Start
  bra     _RTOS_ActionDone

_RTOS_ActionNewTask
  movf    INDF1, w, 0             ;  Current Task can Execute Afterward no matter what
  andlw   0x0F0                   ;  Clear out the Task Number
  movwf   INDF1, 0
  movlw   _fsr1                   ;  Check the Size for Validity
  movff   PLUSW1, PRODL
  movlw   63 + 1           ;  Maximum of 63 Variable Bytes
  subwf   PRODL, w, 0             ;  Make Sure Size isnt' too large. 
  btfsc   STATUS, C, 0
   bra    _RTOS_ActionNewTaskError
  movlw   _fsr0                   ;  Get the Priority and Save it
  movff   PLUSW1, PRODH
  movff   FSR1L, TBLPTRL   ;  Save the contents of FSR1
  movff   FSR1H, TBLPTRH
  movlw   0x077                   ;  Find the New Task Space
  movwf   FSR1L, 0
  clrf    FSR1H, 0
  movlw   0x080                   ;  Point to the First Task
  movwf   FSR2L, 0
  clrf    FSR2H, 0
_RTOS_ActionNewTaskLoop           ;  Loop Here Until Open Task Found
  movf    PREINC1, w, 0           ;  Add to the FSR2 Offset
  btfsc   STATUS, Z
   bra    _RTOS_ActionNewTaskFound
  andlw   0x07F                   ;  Clear Bit 8 if active
  addwf   FSR2L, f, 0
  btfsc   STATUS, C, 0
   incf   FSR2H, f, 0
  movlw   0x07F                   ;  At the End and Nothing Available?
  subwf   FSR1L, w, 0
  btfss   STATUS, Z, 0
   bra    _RTOS_ActionNewTaskLoop
  bra     _RTOS_ActionNewTaskError
_RTOS_ActionNewTaskFound   ;  Have the Task Block that is Available
  movlw   0x018
  addwf   PRODL, f, 0             ;  Get the Task's Size and Put in Blocks
  movff   PRODL, INDF1
  movlw   0x078
  subwf   FSR1L, w, 0             ;  get the Task Number
  movwf   TABLAT, 0
  movff   TBLPTRL, FSR1L   ;  Restore FSR1
  movff   TBLPTRH, FSR1H
  movlw   _wreg                   ;  Update "WREG" with the Created Task Number
  movff   TABLAT, PLUSW1
  movff   FSR2L, TBLPTRL   ;  Save the Block Start Address
  movff   FSR2H, TBLPTRH
  movf    PRODL, w, 0             ;  Clear the Memory
  clrf    POSTINC2, 0     
  decfsz  WREG, f, 0
   bra    $ - (2 * 2)
  movff   TBLPTRL, FSR2L   ;  Restore the Block Start Address
  movff   TBLPTRH, FSR2H
  movf    PRODH, w, 0             ;  Get the Task Priority
  iorlw   0x0C0                   ;  Mark that it is Active
  movwf   INDF2, 0
  movff   FSR1L, PRODL            ;  Save the Source Address
  movff   FSR1H, PRODH
  movlw   _tos_2           ;  Get the Source Address
  addwf   FSR1L, f, 0             ;  Add the Offset to it
  btfsc   STATUS, C, 0
   incf   FSR1H, f, 0
  movff   POSTINC1, TBLPTRL
  movff   POSTINC1, TBLPTRH
  movff   POSTINC1, TABLAT
  movff   FSR2L, PCLATH           ;  Save FSR2 Start for Saving PCLAT Registers
  movff   FSR2H, PCLATU
  movlw   _tos_1           ;  Putin Execution Address
  addwf   FSR2L, f, 0             ;  Add the Offset to it
  btfsc   STATUS, C, 0
   incf   FSR2H, f, 0
  movff   TBLPTRL, POSTINC2
  movff   TBLPTRH, POSTINC2
  movff   TABLAT, POSTINC2
  movff   PCLATH, FSR2L           ;  Setup Pointer to Start
  movff   PCLATU, FSR2H
  movlw   _pclath          ;  Put in the PCLATH Values
  addwf   FSR2L, f, 0
  btfsc   STATUS, C, 0
   incf   FSR2H, f, 0
  movff   TBLPTRH, POSTINC2
  movff   TABLAT, POSTINC2
  movff   PRODL, FSR1L            ;  Save the Source Address
  movff   PRODH, FSR1H
  movlw   _status          ;  Indicate Operation Executed Correctly
  bcf     PLUSW1, C, 0           
  bra     _RTOS_ActionDone
_RTOS_ActionNewTaskError          ;  Set Carry Flag if there is a Problem
  movff   TBLPTRL, FSR1L   ;  Restore FSR1
  movff   TBLPTRH, FSR1H
  movlw   _status
  bsf     PLUSW1, C, 0            ;  Task STATUS is two from the Start
  bra     _RTOS_ActionDone

_RTOS_ActionDone           ;  Finished Executing Request
  movf    POSTINC0, w, 0   ;  Get the Offset to the Next
  andlw   0x07F                   ;  Make Sure Bit 7 Not Set
  addwf   FSR1L, f, 0
  btfsc   STATUS, C, 0
   incf   FSR1H, f, 0
  movf    INDF0, f, 0
  btfsc   STATUS, Z, 0
   bra    _RTOS_ActionEnd  ;  Next Value == 0, Finished with List
  btfss   FSR0L, 7, 0             ;  Are we at 0x080? 
   bra    _RTOS_ActionLoop
_RTOS_ActionEnd

  movlw   0x078                   ;  Look for Tasks that are waiting for messages
  movwf   FSR0L, 0
  clrf    FSR0H, 0
  movlw   0x080                   ;  FSR1 Points to the Offsets
  movwf   FSR1L, 0
  clrf    FSR1H, 0
_RTOS_WaitLoop
  movf    INDF0, f, 0             ;  At End of Task List? 
  btfsc   STATUS, Z, 0
   bra    _RTOS_WaitDone
  movf    INDF1, w, 0             ;  Waiting for a Message? 
  andlw   0x0C0
  xorlw   0x080
  btfss   STATUS, Z, 0
   bra    _RTOS_WaitNext   ;  No - Jump to the Next Task
  movff   FSR1L, PRODL            ;  Save FSR1 and Look for Matches
  movff   FSR1H, PRODH
  movlw   0x078
  movwf   FSR1L, 0
  clrf    FSR1H, 0
  movlw   0x080                   ;  Get the Offsets
  movwf   FSR2L, 0
  clrf    FSR2H, 0
_RTOS_WaitSubLoop          ;  Loop Here for a Match
  movf    INDF1, f, 0             ;  At the End of the List? 
  btfsc   STATUS, Z, 0
   bra    _RTOS_WaitRestoreNext   ;  Yes, No March
  movf    INDF2, w, 0             ;  Check for sending a Value
  andlw   0x0C0
  xorlw   0x040
  btfss   STATUS, Z, 0
   bra    _RTOS_WaitSubNext       ;  No, Check the Next
  movf    INDF2, w, 0             ;  Get the Task Number
  andlw   0x00F
  addlw   0x078    
  xorwf   FSR0L, w, 0             ;  Does it Match the "Get" Task? 
  btfss   STATUS, Z, 0
   bra    _RTOS_WaitSubNext       ;  No, Skip Over
  movf    FSR1L, w, 0
  movff   PRODL, FSR1L            ;  Restore to Look at the Original (for Resetting)
  movwf   PRODL, 0         ;  Save the Offset for Setting up the Destination
  movff   PRODH, FSR1H
  movlw   0x0C0                   ;  Mark that the Task Can Execute
  iorwf   INDF1, f, 0
  movlw   _fsr0                   ;  Move the Data Over
  movff   PLUSW2, PLUSW1
  movlw   _fsr1
  movff   PLUSW2, PLUSW1
  movlw   0x078                   ;  Return the Task Number
  subwf   PRODL, f, 0
  movlw   _wreg
  movff   PRODL, PLUSW1
  bra     _RTOS_WaitNext
_RTOS_WaitSubNext          ;  No Match, Loop Around and Try Again
  movf    POSTINC1, w, 0
  andlw   0x07F
  addwf   FSR2L, f, 0
  btfsc   STATUS, C, 0
   incf   FSR2H, f, 0
  btfss   FSR1L, 7, 0             ;  At Address 0x080? 
   bra    _RTOS_WaitSubLoop
_RTOS_WaitRestoreNext
  movff   PRODL, FSR1L
  movff   PRODH, FSR1H
_RTOS_WaitNext
  movf    POSTINC0, w, 0   ;  Point to the Next Task
  andlw   0x07F
  addwf   FSR1L, f, 0
  btfsc   STATUS, C, 0
   incf   FSR1H, f, 0
  btfss   FSR0L, 7, 0             ;  At the End of the Tasks? 
   bra    _RTOS_WaitLoop
_RTOS_WaitDone

  movlw   0x078                   ;  Find the Next Task to Execute (From Current)
  movwf   FSR0L, 0
  clrf    FSR0H, 0
  movlw   0x080
  movwf   FSR1L, 0
  clrf    FSR1H, 0
_RTOS_ExecuteFind         
  btfsc   INDF0, 7, 0             ;  Is the Execution flag Set? 
   bra    _RTOS_ExecuteFound
  movf    POSTINC0, w, 0
  addwf   FSR1L, f, 0
  btfsc   STATUS, C, 0
   incf   FSR1H, f, 0
  bra     _RTOS_ExecuteFind
_RTOS_ExecuteFound         ;  Have Found Current Task
  movff   FSR0L, PRODL            ;  Record the Start Position
  clrf    PRODH, 0         ;  Record the Next to Execute's
  clrf    FSR2L, 0         ;  Record the Next to Execute's Priority
  clrf    FSR2H, 0
  bcf     INDF0, 7, 0             ;  Clear the Execution Flag
_RTOS_ExecuteLoop
  movf    POSTINC0, w, 0   ;  Jump to the Next Value
  movf    INDF0, f, 0             ;  At the End of the List? 
  btfss   STATUS, Z, 0
   btfsc  FSR0L, 7, 0             ;  Either Next is Zero or Current is == 0x80
    bra   _RTOS_ExecuteWrap       ;  Yes, Wrap Around
  addwf   FSR1L, f, 0             ;  Add it to the Execution List
  btfsc   STATUS, C, 0
   incf   FSR1H, f, 0
  bra     _RTOS_ExecuteCheck
_RTOS_ExecuteWrap          ;  Wrap Execution back to the Start
  movlw   0x078
  movwf   FSR0L, 0
  clrf    FSR0H, 0
  movlw   0x080
  movwf   FSR1L, 0
  clrf    FSR1H, 0
_RTOS_ExecuteCheck         ;  Check to See if Current is Better than Last
  movf    INDF1, w, 0             ;  Check to See if it can Execute
  andlw   0x0C0
  xorlw   0x0C0
  btfss   STATUS, Z
   bra    _RTOS_ExecuteEndCheck   ;  Can't Execute, Check to See if at End
  movf    PRODH, f, 0             ;  Anything Entered Yet? 
  btfsc   STATUS, Z, 0
   bra    _RTOS_ExecuteAdd ;  No - Start with This one
  movf    INDF1, w, 0             ;  Check to See if Current is Higher Priority
  subwf   INDF2, w, 0             ;   than Saved
  btfsc   STATUS, C, 0
   bra    _RTOS_ExecuteEndCheck   ;  It's not
_RTOS_ExecuteAdd
  movff   FSR0L, PRODH            ;  Save the Offset
  movff   FSR1L, FSR2L
  movff   FSR1H, FSR2H
_RTOS_ExecuteEndCheck             ;  At the End? 
  movf    PRODL, w, 0
  xorwf   FSR0L, w, 0
  btfss   STATUS, Z
   bra    _RTOS_ExecuteLoop       ;  No, Look at another one

  movff   PRODH, FSR0L            ;  Point to the Current Value
  clrf    FSR0H, 0
  bsf     INDF0, 7, 0             ;  Mark that it is Executing

  movlw   0x060                   ;  Copy in the TIB Information
  movwf   FSR1L, 0
  clrf    FSR1H, 0
  movlw   0x018
_RTOS_TIBRestore
  movff   POSTINC2, POSTINC1
  decfsz  WREG, f, 0
   bra    _RTOS_TIBRestore
  movf    INDF0, w, 0
  andlw   0x07F                   ;  Clear the Execution Flag
  movwf   PRODL, 0
  movlw   0x018
  subwf   PRODL, w, 0             ;  Copy in the Registers
  btfsc   STATUS, Z, 0
   bra    _RTOS_Restore
  clrf    FSR1L, 0
  clrf    FSR1H, 0
_RTOS_RegRestore
  movff   POSTINC2, POSTINC1
  decfsz  WREG, f, 0
   bra    _RTOS_RegRestore 

_RTOS_Restore              ;  Ready to Resume Execution
  movlw   0x077                   ;  Restore the Registers
  movwf   FSR2L, 0
  clrf    FSR2H, 0
  movlw   3                ;  Restore the Stack
  movwf   FSR0L, 0
_RTOS_RestoreStack
  push
  movf    POSTDEC2, w, 0   ;  Restore the Pushed Addresses
  movwf   TOSU
  movf    POSTDEC2, w, 0
  movwf   TOSH
  movf    POSTDEC2, w, 0
  movwf   TOSL
  decfsz  FSR0L, f, 0
   bra    _RTOS_RestoreStack
  movff   POSTDEC2, FSR1H  ;  Restore the Task Context Registers
  movff   POSTDEC2, FSR1L
  movff   POSTDEC2, FSR0H
  movff   POSTDEC2, FSR0L
  movff   POSTDEC2, PRODH
  movff   POSTDEC2, PRODL
  movff   POSTDEC2, TABLAT
  movff   POSTDEC2, TBLPTRH
  movff   POSTDEC2, TBLPTRL
  movff   POSTDEC2, PCLATU
  movff   POSTDEC2, PCLATH
  movff   POSTDEC2, BSR           ;  Restore the Context Registers
  movff   POSTDEC2, STATUS
  movff   POSTDEC2, WREG  
  retfie

_ATSetup                   ;  Setup the "AllTask" Value

  movlw   (1 << GIE) + (1 << PEIE) + (1 << TMR0IE)
  movwf   INTCON

  movlw   0x098                   ;  Setup the "AllTask" OS Value
  movwf   0x078, 0         ;  Note that it is Active As well
  movlw   7
  movwf   0x060, 0         ;  Clear the Other Task Size Registers
  movlw   0x079
  movwf   FSR0L, 0
  clrf    FSR0H, 0
  clrf    POSTINC0, 0             ;  Clear the Register FSR0 is Pointing to and Increment
  decfsz  0x060, f, 0             ;  Repeat 7x
   bra    $ - (2 * 2)

  push                     ;  Make Sure Stack is Loaded and No UNDERFLOW
  push
  push

  movlw   0x0C0                   ;  Mark that "AllTask" is Executing
  movwf   0x060, 0

_AllTask                   ;  Always Return Here

 TaskStart Task1, 1, 63           ;  Start Application Code

_AllTask_Loop

 TaskNext                  ;  Jump to Next Active Task

  bra     _AllTask_Loop

Task1

 CBLOCK 0x000              ;  Put the Variables Starting at 0x000
LEDTask                           ; 
Counter                           ;  Number of Times Executing
LEDValue
 ENDC

  clrf    Counter, 0              ;  Clear the Variables
  movlw   0x0FF
  movwf   LEDValue

 TaskStart LEDTaskStart, 1, 2     ;  Put in the LED Executing Task
  movwf   LEDTask          ;  Save the Task Number of LEDTask

  movff   LEDValue, FSR0L  ;  Save the LED Task Value
 MsgSend LEDTask
  nop

Task1Loop                  ;  Loop Here Until 64x Past
 
 IntWait 14                ;  Wait for the Timer0 Interrupt

  incf    Counter, f, 0

  movlw   64               ;  Done 64x? 
  xorwf   Counter, w, 0
  btfss   STATUS, Z, 0
   bra    Task1Loop        ;  If Not, Loop Around Again
  movwf   Counter, 0

  decf    LEDValue, f, 0   ;  Increment the LEDs

  movff   LEDValue, FSR0L
 MsgSend LEDTask 

  bra     Task1Loop


LEDTaskStart               ;  Make PORTB Output and Wait for Messages

 CBLOCK 0x000              ;  Variables
LEDTaskNumber
 ENDC

  clrf    TRISB, 0

LEDTaskLoop                ;  Loop Here for Each Character

 MsgWait
  movwf   LEDTaskNumber, 0 ;  Save the Task Number

 MsgRead LEDTaskNumber

  movff   FSR0L, PORTB            ;  Update the LED Value

 MsgAck LEDTaskNumber             ;  Acknowledge the Message

  bra     LEDTaskLoop

  end

No comments: