Line 295... |
Line 295... |
STA R0, TaskMgr.Fault_Flag
|
STA R0, TaskMgr.Fault_Flag
|
LDA R0, TaskMgr.This_Task
|
LDA R0, TaskMgr.This_Task
|
STA R0, TaskMgr.Fault_Task;
|
STA R0, TaskMgr.Fault_Task;
|
.ENDM
|
.ENDM
|
|
|
; TASK_SETUP is a template used to generate code that sets up a single task's
|
; BACKUP_FULL_CONTEXT pushes all 8 registers to the stack
|
; stack and stack pointer for each a task. This macros will temporarily
|
.MACRO BACKUP_FULL_CONTEXT
|
; relocate the stack pointer, push the task's initial state to the task's
|
PSH R0
|
; stack. Note that it is important to also ensure that the stack has data to
|
PSH R1
|
; not only restore the return address, but also R7:R0, as well as the flag
|
PSH R2
|
; state.
|
PSH R3
|
.MACRO TASK_SETUP
|
PSH R4
|
|
PSH R5
|
|
PSH R6
|
|
PSH R7
|
|
.ENDM
|
|
|
; Setup a pointer in R3:R2 to the beginning of the parameter
|
; RESTORE_FULL_CONTEXT pops all 8 registers off of the stack
|
; table to load task information from.
|
.MACRO RESTORE_FULL_CONTEXT
|
LDI R0, #\@
|
POP R7
|
|
POP R6
|
|
POP R5
|
|
POP R4
|
|
POP R3
|
|
POP R2
|
|
POP R1
|
|
POP R0
|
|
.ENDM
|
|
|
|
; REINIT_TASK_TABLE_PTR uses the This_Task variable to configure R3:R2 as a
|
|
; pointer into the TASK_PARAMS table.
|
|
.MACRO REINIT_TASK_TABLE_PTR
|
|
LDA R0, TaskMgr.This_Task
|
LDI R1, #PARAM_TABLE_OFFSET
|
LDI R1, #PARAM_TABLE_OFFSET
|
MUL R1
|
MUL R1
|
|
|
LDA R2, TASK_PARAMS_PTR + 0 ; Load R3:R2 with the start of the
|
LDA R2, TASK_PARAMS_PTR + 0 ; Load R3:R2 with the start of the
|
LDA R3, TASK_PARAMS_PTR + 1 ; task paramenter region
|
LDA R3, TASK_PARAMS_PTR + 1 ; task parameter region
|
|
|
ADD R2
|
ADD R2 ; Add [R3:R2] + [R1:R0] -> [R3:R2]
|
T0X R2
|
T0X R2
|
TX0 R1
|
TX0 R1
|
ADC R3
|
ADC R3
|
T0X R3
|
T0X R3
|
|
.ENDM
|
|
|
|
; SETUP_TASK is a template used to generate code that sets up a single task's
|
|
; stack and stack pointer for each a task. This macros will temporarily
|
|
; relocate the stack pointer, push the task's initial state to the task's
|
|
; stack. Note that it is important to also ensure that the stack has data to
|
|
; not only restore the return address, but also R7:R0, as well as the flag
|
|
; state.
|
|
.MACRO SETUP_TASK
|
|
LDI R0, #\@
|
|
STA R0, TaskMgr.This_Task ; Write This_Task
|
|
|
|
REINIT_TASK_TABLE_PTR ; Use This_Task to initialize R3:R2
|
|
|
; Get the task's starting stack address from the table and load
|
; Get the task's starting stack address from the table and load
|
; it into the CPU SP
|
; it into the CPU SP
|
LDO R2, PARAM_STACK_ADDR_HIGH
|
LDO R2, PARAM_STACK_ADDR_HIGH
|
T0X R1
|
T0X R1
|
Line 328... |
Line 358... |
RELOCATE_SP ; R1:R0 -> CPU SP
|
RELOCATE_SP ; R1:R0 -> CPU SP
|
|
|
; From here on out, the CPU SP is pointing to the target task's
|
; From here on out, the CPU SP is pointing to the target task's
|
; stack region, so we can initialize its stack memory
|
; stack region, so we can initialize its stack memory
|
|
|
; Write initial flag value
|
; Write initial flag value to simulate entering code as an ISR
|
CLR R0
|
CLR R0
|
PSH R0
|
PSH R0
|
|
|
; Initialize the return address to point to the "initialize"
|
; Initialize the return address to point to the "initialize"
|
; portion of the task, so that the task can do its one-time
|
; portion of the task, so that the task can do its one-time
|
Line 344... |
Line 374... |
LDO R2, PARAM_MAIN_ADDR_LOW ; Write return PC LSB
|
LDO R2, PARAM_MAIN_ADDR_LOW ; Write return PC LSB
|
PSH R0
|
PSH R0
|
|
|
; Setup the initial reg values
|
; Setup the initial reg values
|
CLR R0 ; Initialize all registers to 0
|
CLR R0 ; Initialize all registers to 0
|
PSH R0 ; R0
|
T0X R1
|
PSH R0 ; R1
|
|
PSH R0 ; R2
|
|
PSH R0 ; R3
|
|
PSH R0 ; R4
|
|
PSH R0 ; R5
|
|
PSH R0 ; R6
|
|
PSH R0 ; R7
|
|
|
|
; Once the task's stack has been initialized, retrieve the new
|
|
; stack pointer from the SP and store it in the task's backup
|
|
; variable.
|
|
|
|
LDI R0, #\@
|
|
LDI R1, #STACK_TABLE_OFFSET
|
|
MUL R1
|
|
|
|
LDA R2, STACK_MEMORY_PTR + 0
|
|
LDA R3, STACK_MEMORY_PTR + 1
|
|
|
|
ADD R2
|
|
T0X R2
|
T0X R2
|
TX0 R1
|
|
ADC R3
|
|
T0X R3
|
T0X R3
|
|
T0X R4
|
RETRIEVE_SP
|
T0X R5
|
STX R2
|
T0X R6
|
TX0 R1
|
T0X R7
|
STO R2,1
|
|
|
; Once the task's initial state has been created, "suspend"
|
|
; the task. This will effective initialize its state and
|
|
; SP pointer
|
|
SUSPEND_THIS_TASK
|
.ENDM
|
.ENDM
|
|
|
; INSTANCE_TASK_SETUP expands to create setup code for all of the tasks based
|
; SUSPEND_THIS_TASK pushes all of the registers to a task's stack, then
|
; on the template above. There should be one setup per task, hence the repeat
|
; backups up the stack pointer to the system memory backup location for that
|
; based on TASK_COUNT
|
; task.
|
.MACRO INSTANCE_TASK_SETUP
|
.MACRO SUSPEND_THIS_TASK
|
.REPT TASK_COUNT
|
BACKUP_FULL_CONTEXT
|
TASK_SETUP
|
BACKUP_STACK_POINTER
|
.ENDR
|
|
.ENDM
|
.ENDM
|
|
|
; REINIT_STACK_BUFFER_PTR uses the This_Task variable to configure R3:R2 as a
|
; BACKUP_STACK_POINTER uses the This_Task variable to configure R3:R2 as a
|
; pointer into the system memory where stack pointer backups are stored.
|
; pointer into the system memory where stack pointer backups are stored, then
|
.MACRO REINIT_STACK_BUFFER_PTR
|
; obtains the current stack address and pushes it to the task's backup
|
|
; SP variable
|
|
.MACRO BACKUP_STACK_POINTER
|
LDA R0, TaskMgr.This_Task ; Get the task number
|
LDA R0, TaskMgr.This_Task ; Get the task number
|
LDI R1, #STACK_TABLE_OFFSET ; Multiply it by 2
|
LDI R1, #STACK_TABLE_OFFSET ; Multiply it by 2
|
MUL R1
|
MUL R1
|
|
|
LDA R2, STACK_MEMORY_PTR + 0 ; Load R3:R2 with the start of the
|
LDA R2, STACK_MEMORY_PTR + 0 ; Load R3:R2 with the start of the
|
Line 400... |
Line 413... |
ADD R2 ; Add [R3:R2] + [R1:R0] -> [R3:R2]
|
ADD R2 ; Add [R3:R2] + [R1:R0] -> [R3:R2]
|
T0X R2
|
T0X R2
|
TX0 R1
|
TX0 R1
|
ADC R3
|
ADC R3
|
T0X R3
|
T0X R3
|
.ENDM
|
|
|
|
|
|
; REINIT_TASK_TABLE_PTR uses the This_Task variable to configure R3:R2 as a
|
RETRIEVE_SP
|
; pointer into the TASK_PARAMS table.
|
STX R2
|
.MACRO REINIT_TASK_TABLE_PTR
|
TX0 R1
|
|
STO R2,1
|
|
.ENDM
|
|
|
LDA R0, TaskMgr.This_Task
|
; RESTORE_STACK_POINTER uses the This_Task variable to configure R3:R2 as a
|
LDI R1, #PARAM_TABLE_OFFSET
|
; pointer into the system memory where stack pointer backups are stored. It
|
|
; then looks up the task's SP backup variable and pushes it back to the CPU SP
|
|
.MACRO RESTORE_STACK_POINTER
|
|
LDA R0, TaskMgr.This_Task ; Get the task number
|
|
LDI R1, #STACK_TABLE_OFFSET ; Multiply it by 2
|
MUL R1
|
MUL R1
|
|
|
LDA R2, TASK_PARAMS_PTR + 0 ; Load R3:R2 with the start of the
|
LDA R2, STACK_MEMORY_PTR + 0 ; Load R3:R2 with the start of the
|
LDA R3, TASK_PARAMS_PTR + 1 ; task parameter region
|
LDA R3, STACK_MEMORY_PTR + 1 ; stack memory region
|
|
|
ADD R2 ; Add [R3:R2] + [R1:R0] -> [R3:R2]
|
ADD R2 ; Add [R3:R2] + [R1:R0] -> [R3:R2]
|
T0X R2
|
T0X R2
|
TX0 R1
|
TX0 R1
|
ADC R3
|
ADC R3
|
T0X R3
|
T0X R3
|
.ENDM
|
|
|
|
; BACKUP_FULL_CONTEXT pushes all 8 registers to the stack
|
|
.MACRO BACKUP_FULL_CONTEXT
|
|
PSH R0
|
|
PSH R1
|
|
PSH R2
|
|
PSH R3
|
|
PSH R4
|
|
PSH R5
|
|
PSH R6
|
|
PSH R7
|
|
.ENDM
|
|
|
|
; RESTORE_FULL_CONTEXT pops all 8 registers off of the stack
|
|
.MACRO RESTORE_FULL_CONTEXT
|
|
POP R7
|
|
POP R6
|
|
POP R5
|
|
POP R4
|
|
POP R3
|
|
POP R2
|
|
POP R1
|
|
POP R0
|
|
.ENDM
|
|
|
|
; SUSPEND_CURRENT_TASK pushes all of the registers to a task's stack, then
|
|
; backups up the stack pointer to the system memory backup location for that
|
|
; task.
|
|
.MACRO SUSPEND_CURRENT_TASK
|
|
BACKUP_FULL_CONTEXT
|
|
|
|
REINIT_STACK_BUFFER_PTR
|
|
|
|
RETRIEVE_SP ; Copy CPU SP -> R1:R0
|
|
STX R2 ; Push R1:R0 -> [R3:R2]*
|
|
TX0 R1
|
|
STO R2,1
|
|
.ENDM
|
|
|
|
; AWAKEN_NEXT_TASK is responsible for updating the Next_Task variable, then
|
|
; using it to restore the stack pointer from the system memory copy. It then
|
|
; updates the memory write protection parameters and I/O write qualification
|
|
; register for the new task. Finally, it resets the pre-emption timer and
|
|
; restores the register state from the task's stack.
|
|
.MACRO AWAKEN_NEXT_TASK
|
|
LDA R1, TaskMgr.Next_Task ; Copy Next_Task -> This_Task
|
|
STA R1, TaskMgr.This_Task
|
|
|
|
; This is a simple round-robin scheduler, unless an ISR alters the Next_Task
|
|
; variable, so increment the task count, check it against the total task
|
|
; count, and reset it to task 0 if necessary.
|
|
|
|
INC R1 ; Increment the task count
|
|
LDI R0, #TASK_COUNT ; Compare it with the task count
|
|
XOR R1
|
|
BNZ _TS_ADV_TN_\@ ; If it matches the task count
|
|
LDI R1, #$00 ; reset the counter to zero
|
|
_TS_ADV_TN_\@:STA R1, TaskMgr.Next_Task ; Store the new value into Next_Task
|
|
|
|
REINIT_STACK_BUFFER_PTR ; Lookup the new task's table pointer
|
|
LDO R2,1 ; Copy [R3:R2]* -> R1:R0
|
LDO R2,1 ; Copy [R3:R2]* -> R1:R0
|
T0X R1
|
T0X R1
|
LDX R2
|
LDX R2
|
RELOCATE_SP ; Update R1:R0 -> CPU SP
|
RELOCATE_SP ; Update R1:R0 -> CPU SP
|
|
.ENDM
|
|
|
|
; RESTORE_TASK_PERMISSIONS looks up the current (new) task's RAM & I/O write
|
|
; permissions (masks) and reconfigures the hardware to allow access.
|
|
.MACRO RESTORE_TASK_PERMISSIONS
|
REINIT_TASK_TABLE_PTR ; Setup R3:R2 to point to the task table
|
REINIT_TASK_TABLE_PTR ; Setup R3:R2 to point to the task table
|
|
|
; Rewrite the RAM WPR register for this task. Note that the WPR
|
; Rewrite the RAM WPR register for this task. Note that the WPR
|
; is a 32-bit register.
|
; is a 32-bit register.
|
LDO R2, PARAM_WPR_BYTE0
|
LDO R2, PARAM_WPR_BYTE0
|
Line 503... |
Line 464... |
LDO R2, PARAM_WPR_BYTE3
|
LDO R2, PARAM_WPR_BYTE3
|
STA R0, WPR_MASK_3
|
STA R0, WPR_MASK_3
|
|
|
LDO R2, PARAM_WQL_LOW ; Update the new task's WQL
|
LDO R2, PARAM_WQL_LOW ; Update the new task's WQL
|
STA R0, IO_WRITE_QUAL
|
STA R0, IO_WRITE_QUAL
|
|
.ENDM
|
|
|
RESET_PREEMPTION_TIMER ; Reset the PIT timer
|
; INIT_NEXT_TASK forces the Next_Task variable to 0 (Task 0)
|
|
.MACRO INIT_NEXT_TASK
|
|
CLR R0
|
|
STA R0, TaskMgr.Next_Task
|
|
.ENDM
|
|
|
|
; ADVANCE_NEXT_TASK implements the simple scheduler. By default, the task
|
|
; manager uses a simple round-robin scheduler, unless an ISR alters the
|
|
; Next_Task variable, so increment the task count, check it against the
|
|
; total task count, and reset it to task 0 if necessary.
|
|
.MACRO ADVANCE_NEXT_TASK
|
|
LDA R1, TaskMgr.Next_Task ; Copy Next_Task -> This_Task
|
|
STA R1, TaskMgr.This_Task
|
|
|
|
INC R1 ; Increment the task count
|
|
LDI R0, #TASK_COUNT ; Compare it with the task count
|
|
XOR R1
|
|
BNZ _TS_ADV_TN_\@ ; If it matches the task count
|
|
LDI R1, #$00 ; reset the counter to zero
|
|
_TS_ADV_TN_\@:STA R1, TaskMgr.Next_Task ; Store the new value into Next_Task
|
|
.ENDM
|
|
|
|
; AWAKEN_NEXT_TASK is responsible for updating the Next_Task variable, then
|
|
; using it to restore the stack pointer from the system memory copy. It then
|
|
; updates the memory write protection parameters and I/O write qualification
|
|
; register for the new task. Finally, it resets the pre-emption timer and
|
|
; restores the register state from the task's stack.
|
|
.MACRO AWAKEN_NEXT_TASK
|
|
ADVANCE_NEXT_TASK ; Advance the task positions
|
|
RESTORE_STACK_POINTER ; Lookup the new task's table pointer
|
|
RESTORE_TASK_PERMISSIONS ; Restore the task's write access masks
|
|
RESET_PREEMPTION_TIMER ; Reset the PIT timer
|
RESTORE_FULL_CONTEXT ; Restore the new task's register state
|
RESTORE_FULL_CONTEXT ; Restore the new task's register state
|
RTI
|
RTI ; Return to the new task
|
.ENDM
|
.ENDM
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; System Start
|
; System Start
|
Line 521... |
Line 513... |
; in supervisor mode, something has gone horribly wrong. This branch locks the
|
; in supervisor mode, something has gone horribly wrong. This branch locks the
|
; main loop if the I bit is not set. This is probably unnecessary now that the
|
; main loop if the I bit is not set. This is probably unnecessary now that the
|
; panic ISR is in place.
|
; panic ISR is in place.
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
|
|
; INIT_NEXT_TASK forces the Next_Task variable to 0 (Task 0)
|
; INSTANCE_TASK_SETUP expands to create setup code for all of the tasks based
|
.MACRO INIT_NEXT_TASK
|
; on the template above. There should be one setup per task, hence the repeat
|
CLR R0
|
; based on TASK_COUNT
|
STA R0, TaskMgr.Next_Task
|
.MACRO INSTANCE_TASK_SETUP
|
|
.REPT TASK_COUNT
|
|
SETUP_TASK
|
|
.ENDR
|
.ENDM
|
.ENDM
|
|
|
.MACRO BOOT_SYSTEM
|
.MACRO BOOT_SYSTEM
|
; Before beginning, turn off all of the CPU interrupts (The NMI will still be
|
; Before beginning, turn off all of the CPU interrupts (The NMI will still be
|
; active, but memory write protection is effectively disabled with the I-bit
|
; active, but memory write protection is effectively disabled with the I-bit
|
Line 561... |
Line 556... |
.ENDIF
|
.ENDIF
|
; Once the external interrupt manager is configured, enable the CPU interrupts
|
; Once the external interrupt manager is configured, enable the CPU interrupts
|
ENABLE_CPU_INTS ; Enable the CPU interrupt inputs
|
ENABLE_CPU_INTS ; Enable the CPU interrupt inputs
|
|
|
; Like the task switcher ISR, restore the full CPU state for the first task
|
; Like the task switcher ISR, restore the full CPU state for the first task
|
INIT_NEXT_TASK
|
INIT_NEXT_TASK ; Reset the next task to task 0
|
AWAKEN_NEXT_TASK
|
AWAKEN_NEXT_TASK ; Load task 0's context to system
|
|
|
; Create all of the task loops here.
|
; Create all of the task loops here.
|
INSTANCE_TASK_LOOPS
|
INSTANCE_TASK_LOOPS ; Instantiate the main task loops
|
.ENDM
|
.ENDM
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Task Loops
|
; Task Loops
|
Line 719... |
Line 714... |
;
|
;
|
; Handles switching context between tasks when called.
|
; Handles switching context between tasks when called.
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
|
|
.MACRO SWITCH_TASKS
|
.MACRO SWITCH_TASKS
|
SUSPEND_CURRENT_TASK
|
SUSPEND_THIS_TASK
|
AWAKEN_NEXT_TASK
|
AWAKEN_NEXT_TASK
|
.ENDM
|
.ENDM
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
|
|