OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [taskmgr/] [taskmgr_const.s] - Blame information for rev 305

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 301 jshamlet
; Copyright (c)2022 Jeremy Seth Henry
2
; All rights reserved.
3
;
4
; Redistribution and use in source and binary forms, with or without
5
; modification, are permitted provided that the following conditions are met:
6
;     * Redistributions of source code must retain the above copyright
7
;       notice, this list of conditions and the following disclaimer.
8
;     * Redistributions in binary form must reproduce the above copyright
9
;       notice, this list of conditions and the following disclaimer in the
10
;       documentation and/or other materials provided with the distribution,
11
;       where applicable (as part of a user interface, debugging port, etc.)
12
;
13
; THIS SOFTWARE IS PROVIDED BY JEREMY SETH HENRY ``AS IS'' AND ANY
14
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
; DISCLAIMED. IN NO EVENT SHALL JEREMY SETH HENRY BE LIABLE FOR ANY
17
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22
; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
;
24
;------------------------------------------------------------------------------
25
; taskmgr_const.s
26
;
27
;  Task Manager constants, tables, and macros
28
;
29
; Revision History
30
; Author          Date     Change
31
;---------------- -------- ----------------------------------------------------
32
; Seth Henry      7/15/22  Initial Release
33
;------------------------------------------------------------------------------
34
 
35
;------------------------------------------------------------------------------
36
; Semaphore Value - should always be non-zero
37
.DEFINE SEMAPHORE_VAL        $FF       ; Standard value used to set semaphores
38
;------------------------------------------------------------------------------
39
 
40
;------------------------------------------------------------------------------
41
; I/O Mapping (HDL -> ASSY)
42
;------------------------------------------------------------------------------
43
 
44
; System RAM Write-Protect Register
45
.DEFINE WPR_MASK_REG         WPR_Address
46
 
47
; Write Protect Mask
48
.DEFINE WPR_MASK_0           WPR_MASK_REG + 0
49
.DEFINE WPR_MASK_1           WPR_MASK_REG + 1
50
.DEFINE WPR_MASK_2           WPR_MASK_REG + 2
51
.DEFINE WPR_MASK_3           WPR_MASK_REG + 3
52
 
53
; WP Register Map:
54
; Offset  Bitfield Description                        Read/Write
55
;   0x00  AAAAAAAA Region Enables  7:0                  (RW)
56
;   0x01  AAAAAAAA Region Enables 15:8                  (RW)
57
;   0x02  AAAAAAAA Region Enables 23:16                 (RW)
58
;   0x03  AAAAAAAA Region Enables 31:24                 (RW)
59
 
60
; I/O Write Qualification Register
61
.DEFINE IO_WRITE_QUAL        WQL_Address
62
 
63
; External Interrupt Manager / Task Timer
64
.DEFINE INT_MGR_IF           INT_Address ; Shared with the main
65
.DEFINE TASK_TIMER_PRD       INT_MGR_IF  + 0
66
 
67
; Defines for the 8-bit interrupt manager
68
.DEFINE EXT_INT_MASK         INT_MGR_IF + 1
69
.DEFINE EXT_INT_PEND         INT_MGR_IF + 2
70
.DEFINE EXT_INT_ACK          INT_MGR_IF + 3
71
 
72
; Defines for the 16-bit interrupt manager
73
.DEFINE EXT_INT16_MASK_L     INT_MGR_IF + 2
74
.DEFINE EXT_INT16_MASK_H     INT_MGR_IF + 3
75
.DEFINE EXT_INT16_PEND_L     INT_MGR_IF + 4
76
.DEFINE EXT_INT16_PEND_H     INT_MGR_IF + 5
77
.DEFINE EXT_INT16_ACK        INT_MGR_IF + 7
78
 
79
; Register Map:
80
; Offset  Bitfield Description                        Read/Write
81
;   0x00  AAAAAAAA PIT Timer Interval (0 = disabled)    (RW)
82
;   0x01  AAAAAAAA External Interrupt Mask              (RW)
83
;   0x02  AAAAAAAA Pending External Ints*               (RW)
84
;   0x02  A------- Interrupt Requested (write to clear) (RW)
85
 
86
; External Interrupt bit & mask definitions
87
.DEFINE EXT_INT0_BIT         2^0
88
.DEFINE EXT_INT1_BIT         2^1
89
.DEFINE EXT_INT2_BIT         2^2
90
.DEFINE EXT_INT3_BIT         2^3
91
.DEFINE EXT_INT4_BIT         2^4
92
.DEFINE EXT_INT5_BIT         2^5
93
.DEFINE EXT_INT6_BIT         2^6
94
.DEFINE EXT_INT7_BIT         2^7
95
 
96
.DEFINE EXT_INT8_BIT         2^0
97
.DEFINE EXT_INT9_BIT         2^1
98
.DEFINE EXT_INT10_BIT        2^2
99
.DEFINE EXT_INT11_BIT        2^3
100
.DEFINE EXT_INT12_BIT        2^4
101
.DEFINE EXT_INT13_BIT        2^5
102
.DEFINE EXT_INT14_BIT        2^6
103
.DEFINE EXT_INT15_BIT        2^7
104
;------------------------------------------------------------------------------
105
 
106
;------------------------------------------------------------------------------
107
; Register the interrupt service routines and form the vector address table at
108
;  the end of the ROM
109
;------------------------------------------------------------------------------
110
.ORG ISR_Start_Addr
111
.DW RAM_FAULT        ; (0xFFF1:0xFFF0) ISR 0
112
.DW TASK_SW_INT      ; (0xFFF3:0xFFF2) ISR 1
113
.DW EXT_INT_MGR      ; (0xFFF5:0xFFF4) ISR 2
114
.DW EXEC_SUPV0       ; (0xFFF7:0xFFF6) ISR 3
115
.DW EXEC_SUPV1       ; (0xFFF9:0xFFF8) ISR 4
116
.DW EXEC_SUPV2       ; (0xFFFB:0xFFFA) ISR 5
117
.DW EXEC_SUPV3       ; (0xFFFD:0xFFFC) ISR 6
118
.DW EXEC_SUPV4       ; (0xFFFF:0xFFFE) ISR 7
119
 
120
.DEFINE CPU_INT_ENABLES      $FF
121
;------------------------------------------------------------------------------
122
 
123
;------------------------------------------------------------------------------
124
; Pointer Defines and Table Organization
125
;------------------------------------------------------------------------------
126
 
127
; Create defined constants to pointer table
128
; Note that these are offset by 4 to account for the bootstrap JMP and NOP
129
.DEFINE STACK_MEMORY_PTR     BOOT_BLOCK +  4
130
.DEFINE FREE_SYSMEM_PTR      BOOT_BLOCK +  6
131
.DEFINE TASK_PARAMS_PTR      BOOT_BLOCK +  8
132
.DEFINE TASK_PARAM_TABLE     BOOT_BLOCK +  10
133
 
134
.MACRO INSTANCE_TASK_POINTERS
135
 
136
.DW TaskMgr.Task_Stacks   ; ( + 4) First available RAM location for stack data
137
.DW TaskMgr.Free_Mem      ; ( + 6) First available free RAM location in sysmem
138
.DW TASK_PARAM_TABLE      ; ( + 8) Start of task parameter table
139
.ENDM
140
 
141
;------------------------------------------------------------------------------
142
; INSTANCE_TASK_EXPORTS / CREATE_TASK_EXPORTS setup a ROM table for the task
143
;  switcher with critical entry points and memory & I/O write access
144
;  permissions. The entry points are created automatically by
145
;  INSTANCE_MAIN_LOOPS, while the other constants are setup in taskmgr_config.s
146
;  based on its task configuration and memory needs
147
;------------------------------------------------------------------------------
148
 
149
.DEFINE STACK_TABLE_OFFSET    2
150
.DEFINE PARAM_TABLE_OFFSET   20
151
 
152
; Define table offsets to allow quick use of LDO to access individual records
153
;  for each task
154
 
155
.DEFINE PARAM_MAIN_ADDR_LOW   0
156
.DEFINE PARAM_MAIN_ADDR_HIGH  1
157
 
158
.DEFINE PARAM_STACK_ADDR_LOW  2
159
.DEFINE PARAM_STACK_ADDR_HIGH 3
160
 
161
.DEFINE PARAM_WPR_BYTE0       4
162
.DEFINE PARAM_WPR_BYTE1       5
163
.DEFINE PARAM_WPR_BYTE2       6
164
.DEFINE PARAM_WPR_BYTE3       7
165
 
166
.DEFINE PARAM_WQL_LOW         8
167
.DEFINE PARAM_WQL_HIGH        9
168
 
169
.DEFINE SUPV_FN0_ENTRY_LOW    10
170
.DEFINE SUPV_FN0_ENTRY_HIGH   11
171
 
172
.DEFINE SUPV_FN1_ENTRY_LOW    12
173
.DEFINE SUPV_FN1_ENTRY_HIGH   13
174
 
175
.DEFINE SUPV_FN2_ENTRY_LOW    14
176
.DEFINE SUPV_FN2_ENTRY_HIGH   15
177
 
178
.DEFINE SUPV_FN3_ENTRY_LOW    16
179
.DEFINE SUPV_FN3_ENTRY_HIGH   17
180
 
181
.DEFINE SUPV_FN4_ENTRY_LOW    18
182
.DEFINE SUPV_FN4_ENTRY_HIGH   19
183
 
184
; CREATE_TASK_EXPORTS creates an entry in the TASK_PARAM_TABLE with critical
185
;  task information. Note that the WPR_LOW, WPR_HIGH, and WQL must be defined
186
;  in taskmgr_config.s. Everything else is automatically created here, or by
187
;  the assembler/linker.
188
 
189
.MACRO CREATE_TASK_EXPORTS
190
.DEFINE TASK\@_STACK_END      RAM_Address + (TASK\@_STACK_RGN * WP_Rgn_Size)
191
.DEFINE TASK\@_STACK_START    TASK\@_STACK_END + WP_Rgn_Size - 1
192
 
193
.DW TASK\@_MAIN          ; 1:0 Entry point created by INSTANCE_MAIN_LOOPS
194
.DW TASK\@_STACK_START   ; 3:2 Pointer to top of the task stack
195
.DW TASK\@_WPR_LOW       ; 5:4 Mask for enabling task mem writes for vars
196
.DW TASK\@_WPR_HIGH      ; 7:6 Mask for enabling task mem writes for stack
197
.DW TASK\@_WQL           ; 9:8 Mask for enabling task I/O write access
198
.DW _F0_EXE_S\@          ; 11:10 Entry point for supervisory function 0
199
.DW _F1_EXE_S\@          ; 13:12 Entry point for supervisory function 1
200
.DW _F2_EXE_S\@          ; 15:14 Entry point for supervisory function 2
201
.DW _F3_EXE_S\@          ; 17:16 Entry point for supervisory function 3
202
.DW _F4_EXE_S\@          ; 19:18 Entry point for supervisory function 4
203
.ENDM
204
 
205
.MACRO INSTANCE_TASK_EXPORTS
206
    .REPEAT TASK_COUNT
207
        CREATE_TASK_EXPORTS
208
    .ENDR
209
.ENDM
210
;------------------------------------------------------------------------------
211
 
212
;------------------------------------------------------------------------------
213
;  Memory Structures and Variable Organization
214
;------------------------------------------------------------------------------
215
 
216
; Variable    Size      Description
217
; --------    ----      -------------------------------------------------------
218
.STRUCT str_task_label
219
Label         DW        ; 2-byte "header" to allow task RAM to be easily found
220
.ENDST
221
 
222
.STRUCT str_isr_flag
223
Flag          DB        ; Single-byte flag variable for returning semaphores
224
.ENDST
225
 
226 302 jshamlet
.DEFINE TSB_SIZE             2 * TASK_COUNT
227
.DEFINE FREE_SYS             WP_Rgn_Size - 8 - TSB_SIZE
228 301 jshamlet
 
229
.STRUCT str_taskman
230
This_Task     DB           ; Holds the task number of the current task
231
Next_Task     DB           ; Specifieds which task to be executed next
232
Fault_Flag    DB           ; Memory write fault flag
233
Fault_Task    DB           ; Task active/responsible for write fault
234 302 jshamlet
Temp_R0       DB           ; Temp storage for R0
235
Temp_R1       DB           ; Temp storage for R1
236
Temp_R2       DB           ; Temp storage for R2
237
Temp_R3       DB           ; Temp storage for R3
238 301 jshamlet
Task_Stacks   DSB TSB_SIZE ; First location for stack data*
239
Free_Mem      DSB FREE_SYS ; Unused memory in system region
240
.ENDST
241
 
242
; * Note that this location is used to setup a pointer, which the task manager
243
;  will use to assign each task a backup location for its current stack pointer
244
;  Thus, this area grows up to 2x the number tasks. The type is intentionally
245
;  set as DB as a reminder. If attempting to reuse memory in this region, this
246
;  should be noted
247
 
248
.ENUM SYSTEM_VARMEM
249
TaskMgr       INSTANCEOF str_taskman
250
.ENDE
251
;------------------------------------------------------------------------------
252
 
253
;------------------------------------------------------------------------------
254
; Utility macros for booting the system and providing access to internal vars
255
;------------------------------------------------------------------------------
256
 
257
; The Open8 supports an optional mode for the RSP instruction that
258
;  converts it from Reset Stack Pointer to Relocate Stack Pointer.
259
; The new form of the instruction takes one of the CPU flags as a
260
;  direction/mode bit. Setting PSR_S will cause the instruction
261
;  to write R1:R0 -> SP, while clearing it will cause the instruction
262
;  to copy the SP -> R1:R0.
263
 
264
.MACRO RETRIEVE_SP
265
              CLP  PSR_S   ; Affirmatively clear PSR_S flag first
266
              RSP          ; Then execute the RSP instruction
267
.ENDM
268
 
269
.MACRO RELOCATE_SP
270
              STP  PSR_S   ; Affirmatively set PSR_S flag first
271
              RSP          ; Execute the RSP instruction
272
              CLP  PSR_S   ; Reset PSR_GP4 afterward
273
.ENDM
274
 
275
; Task initialization, switching time, and init/exec macros
276
.MACRO DISABLE_PREEMPTION_TIMER
277
              CLR  R0                     ; Make sure the PIT is disabled
278
              STA  R0, TASK_TIMER_PRD     ; by writing 0 to the PIT period
279
.ENDM
280
 
281
.MACRO RESET_PREEMPTION_TIMER
282
              LDI  R0, #MAX_TASK_TIMESLICE; Turn on the PIT timer at this point
283
              STA  R0, TASK_TIMER_PRD     ;  to kick off the task switcher
284
.ENDM
285
 
286
; Fault flag macros
287
.MACRO INITIALIZE_FAULT_FLAGS
288
              CLR  R0
289
              STA  R0, TaskMgr.Fault_Flag
290
              STA  R0, TaskMgr.Fault_Task
291
.ENDM
292
 
293
.MACRO SET_FAULT_FLAGS
294
              LDI  R0, #SEMAPHORE_VAL
295
              STA  R0, TaskMgr.Fault_Flag
296
              LDA  R0, TaskMgr.This_Task
297
              STA  R0, TaskMgr.Fault_Task;
298
.ENDM
299
 
300 304 jshamlet
; BACKUP_FULL_CONTEXT pushes all 8 registers to the stack
301
.MACRO BACKUP_FULL_CONTEXT
302
              PSH  R0
303
              PSH  R1
304
              PSH  R2
305
              PSH  R3
306
              PSH  R4
307
              PSH  R5
308
              PSH  R6
309
              PSH  R7
310
.ENDM
311 301 jshamlet
 
312 304 jshamlet
; RESTORE_FULL_CONTEXT pops all 8 registers off of the stack
313
.MACRO RESTORE_FULL_CONTEXT
314
              POP  R7
315
              POP  R6
316
              POP  R5
317
              POP  R4
318
              POP  R3
319
              POP  R2
320
              POP  R1
321
              POP  R0
322
.ENDM
323
 
324
; REINIT_TASK_TABLE_PTR uses the This_Task variable to configure R3:R2 as a
325
;  pointer into the TASK_PARAMS table.
326
.MACRO REINIT_TASK_TABLE_PTR
327
              LDA  R0, TaskMgr.This_Task
328 301 jshamlet
              LDI  R1, #PARAM_TABLE_OFFSET
329
              MUL  R1
330
 
331
              LDA  R2, TASK_PARAMS_PTR + 0  ; Load R3:R2 with the start of the
332 304 jshamlet
              LDA  R3, TASK_PARAMS_PTR + 1  ;  task parameter region
333 301 jshamlet
 
334 304 jshamlet
              ADD  R2                       ; Add [R3:R2] + [R1:R0] -> [R3:R2]
335 301 jshamlet
              T0X  R2
336
              TX0  R1
337
              ADC  R3
338
              T0X  R3
339 304 jshamlet
.ENDM
340 301 jshamlet
 
341 305 jshamlet
; INITIALIZE_TASK_STACK relocates the CPU stack pointer during setup, then
342
;  simulates an RTI by loading an initial flag and return address, then resets
343
;  all registers to 0
344
.MACRO INITIALIZE_TASK_STACK
345 301 jshamlet
              ; Get the task's starting stack address from the table and load
346
              ;  it into the CPU SP
347
              LDO  R2, PARAM_STACK_ADDR_HIGH
348
              T0X  R1
349
              LDO  R2, PARAM_STACK_ADDR_LOW
350
              RELOCATE_SP                 ; R1:R0 -> CPU SP
351
 
352
              ; From here on out, the CPU SP is pointing to the target task's
353
              ;  stack region, so we can initialize its stack memory
354
 
355 304 jshamlet
              ; Write initial flag value to simulate entering code as an ISR
356 301 jshamlet
              CLR  R0
357
              PSH  R0
358
 
359
              ; Initialize the return address to point to the "initialize"
360
              ;  portion of the task, so that the task can do its one-time
361
              ;  startup code.
362
 
363
              LDO  R2, PARAM_MAIN_ADDR_HIGH ; Write return PC MSB
364
              PSH  R0
365
 
366
              LDO  R2, PARAM_MAIN_ADDR_LOW  ; Write return PC LSB
367
              PSH  R0
368
 
369
              ; Setup the initial reg values
370
              CLR  R0                  ; Initialize all registers to 0
371 304 jshamlet
              T0X  R1
372
              T0X  R2
373
              T0X  R3
374
              T0X  R4
375
              T0X  R5
376
              T0X  R6
377
              T0X  R7
378
.ENDM
379 301 jshamlet
 
380 304 jshamlet
; BACKUP_STACK_POINTER uses the This_Task variable to configure R3:R2 as a
381
;  pointer into the system memory where stack pointer backups are stored, then
382
;  obtains the current stack address and pushes it to the task's backup
383
;  SP variable
384
.MACRO BACKUP_STACK_POINTER
385
              LDA  R0, TaskMgr.This_Task    ; Get the task number
386
              LDI  R1, #STACK_TABLE_OFFSET  ; Multiply it by 2
387 301 jshamlet
              MUL  R1
388
 
389 304 jshamlet
              LDA  R2, STACK_MEMORY_PTR + 0 ; Load R3:R2 with the start of the
390
              LDA  R3, STACK_MEMORY_PTR + 1 ;  stack memory region
391 301 jshamlet
 
392 304 jshamlet
              ADD  R2                  ; Add [R3:R2] + [R1:R0] -> [R3:R2]
393 301 jshamlet
              T0X  R2
394
              TX0  R1
395
              ADC  R3
396
              T0X  R3
397
 
398
              RETRIEVE_SP
399
              STX  R2
400
              TX0  R1
401
              STO  R2,1
402
.ENDM
403
 
404 305 jshamlet
; SUSPEND_THIS_TASK pushes all of the registers to a task's stack, then
405
;  backups up the stack pointer to the system memory backup location for that
406
;  task.
407
.MACRO SUSPEND_THIS_TASK
408
              BACKUP_FULL_CONTEXT
409
              BACKUP_STACK_POINTER
410
.ENDM
411
 
412
; SETUP_TASK is a template used to generate code that sets up a single task's
413
; stack and stack pointer for each a task. This macros will temporarily
414
;  relocate the stack pointer, push the task's initial state to the task's
415
;  stack. Note that it is important to also ensure that the stack has data to
416
;  not only restore the return address, but also R7:R0, as well as the flag
417
;  state.
418
.MACRO SETUP_TASK
419
              LDI  R0, #\@
420
              STA  R0, TaskMgr.This_Task ; Write This_Task
421
 
422
              REINIT_TASK_TABLE_PTR      ; Use This_Task to initialize R3:R2
423
              INITIALIZE_TASK_STACK      ; Setup the new task's stack area
424
              SUSPEND_THIS_TASK          ; Suspend the task to store setup
425
.ENDM
426
 
427 304 jshamlet
; RESTORE_STACK_POINTER uses the This_Task variable to configure R3:R2 as a
428
;  pointer into the system memory where stack pointer backups are stored. It
429
;  then looks up the task's SP backup variable and pushes it back to the CPU SP
430
.MACRO RESTORE_STACK_POINTER
431 301 jshamlet
              LDA  R0, TaskMgr.This_Task    ; Get the task number
432
              LDI  R1, #STACK_TABLE_OFFSET  ; Multiply it by 2
433
              MUL  R1
434
 
435
              LDA  R2, STACK_MEMORY_PTR + 0 ; Load R3:R2 with the start of the
436
              LDA  R3, STACK_MEMORY_PTR + 1 ;  stack memory region
437
 
438
              ADD  R2                  ; Add [R3:R2] + [R1:R0] -> [R3:R2]
439
              T0X  R2
440
              TX0  R1
441
              ADC  R3
442
              T0X  R3
443
 
444 303 jshamlet
              LDO  R2,1                ; Copy [R3:R2]* -> R1:R0
445 301 jshamlet
              T0X  R1
446 303 jshamlet
              LDX  R2
447 301 jshamlet
              RELOCATE_SP              ; Update R1:R0 -> CPU SP
448 304 jshamlet
.ENDM
449 301 jshamlet
 
450 304 jshamlet
; RESTORE_TASK_PERMISSIONS looks up the current (new) task's RAM & I/O write
451
;  permissions (masks) and reconfigures the hardware to allow access.
452
.MACRO RESTORE_TASK_PERMISSIONS
453 301 jshamlet
              REINIT_TASK_TABLE_PTR    ; Setup R3:R2 to point to the task table
454
 
455
              ; Rewrite the RAM WPR register for this task. Note that the WPR
456
              ; is a 32-bit register.
457
              LDO  R2, PARAM_WPR_BYTE0
458
              STA  R0, WPR_MASK_0
459
 
460
              LDO  R2, PARAM_WPR_BYTE1
461
              STA  R0, WPR_MASK_1
462
 
463
              LDO  R2, PARAM_WPR_BYTE2
464
              STA  R0, WPR_MASK_2
465
 
466
              LDO  R2, PARAM_WPR_BYTE3
467
              STA  R0, WPR_MASK_3
468
 
469
              LDO  R2, PARAM_WQL_LOW   ; Update the new task's WQL
470
              STA  R0, IO_WRITE_QUAL
471 304 jshamlet
.ENDM
472 301 jshamlet
 
473 304 jshamlet
; INIT_NEXT_TASK forces the Next_Task variable to 0 (Task 0)
474
.MACRO INIT_NEXT_TASK
475
              CLR  R0
476
              STA  R0, TaskMgr.Next_Task
477
.ENDM
478
 
479
; ADVANCE_NEXT_TASK implements the simple scheduler. By default, the task
480
; manager uses a simple round-robin scheduler, unless an ISR alters the
481
;  Next_Task variable, so increment the task count, check it against the
482
;  total task count, and reset it to task 0 if necessary.
483
.MACRO ADVANCE_NEXT_TASK
484
              LDA  R1, TaskMgr.Next_Task ; Copy Next_Task -> This_Task
485
              STA  R1, TaskMgr.This_Task
486
 
487
              INC  R1                  ; Increment the task count
488
              LDI  R0, #TASK_COUNT     ; Compare it with the task count
489
              XOR  R1
490
              BNZ _TS_ADV_TN_\@        ; If it matches the task count
491
              LDI  R1, #$00            ;  reset the counter to zero
492
_TS_ADV_TN_\@:STA  R1, TaskMgr.Next_Task ; Store the new value into Next_Task
493
.ENDM
494
 
495
; AWAKEN_NEXT_TASK is responsible for updating the Next_Task variable, then
496
;  using it to restore the stack pointer from the system memory copy. It then
497
;  updates the memory write protection parameters and I/O write qualification
498
;  register for the new task. Finally, it resets the pre-emption timer and
499
;  restores the register state from the task's stack.
500
.MACRO AWAKEN_NEXT_TASK
501
              ADVANCE_NEXT_TASK        ; Advance the task positions
502
              RESTORE_STACK_POINTER    ; Lookup the new task's table pointer
503
              RESTORE_TASK_PERMISSIONS ; Restore the task's write access masks
504 301 jshamlet
              RESET_PREEMPTION_TIMER   ; Reset the PIT timer
505
              RESTORE_FULL_CONTEXT     ; Restore the new task's register state
506 304 jshamlet
              RTI                      ; Return to the new task
507 301 jshamlet
.ENDM
508
;------------------------------------------------------------------------------
509
 
510
;------------------------------------------------------------------------------
511
; System Start
512
;
513
; System initialization requires that the CPU start in supervisor mode, as it
514
;  writes to every active region in memory. Thus, if the CPU is NOT in
515
;  in supervisor mode, something has gone horribly wrong. This branch locks the
516
;  main loop if the I bit is not set. This is probably unnecessary now that the
517
;  panic ISR is in place.
518
;------------------------------------------------------------------------------
519
 
520 304 jshamlet
; INSTANCE_TASK_SETUP expands to create setup code for all of the tasks based
521
;  on the template above. There should be one setup per task, hence the repeat
522
;  based on TASK_COUNT
523
.MACRO INSTANCE_TASK_SETUP
524
          .REPT TASK_COUNT
525
              SETUP_TASK
526
          .ENDR
527 301 jshamlet
.ENDM
528
 
529
.MACRO BOOT_SYSTEM
530
; Before beginning, turn off all of the CPU interrupts (The NMI will still be
531
;  active, but memory write protection is effectively disabled with the I-bit
532
;  set) Note that this code is running in interrupt context (I-bit is set)
533
;  so it is "uninterruptible" due to the HDL generic being set. However, this
534
;  doesn't prevent pending interrupts from being latched by the CPU.
535
; Note that this macro is defined in "isr_const.s"
536
              DISABLE_CPU_INTS
537
 
538
; Even though interrupts are off, disable the task timer so that there isn't
539
;  a pending task timer interrupt waiting when interrupts are re-enabled. This
540
;  avoids the first task missing out on initialization.
541
              DISABLE_PREEMPTION_TIMER
542
 
543
; Initialize the system fault flags
544
              INITIALIZE_FAULT_FLAGS
545
 
546
; Setup the stack and stack pointer for each of the tasks. (see above)
547
              INSTANCE_TASK_SETUP
548
 
549
; Before starting, make sure the external interrupt controller has been
550
;  initialized. Initialization of the external interrupt controller involves
551
;  clearing any pending interrupts and setting up the interrupt mask. Finally,
552
;  the CPU interrupts should be enabled at this point, as the interrupt core is
553
;  ready.
554
.IFDEF INTMGR16
555
              INITIALIZE_IO_INTMGR16      ; Setup the 16-bit IF
556
.ELSE
557
              INITIALIZE_IO_INTMGR        ; Setup the 8-bit IF
558
.ENDIF
559
; Once the external interrupt manager is configured, enable the CPU interrupts
560
              ENABLE_CPU_INTS             ; Enable the CPU interrupt inputs
561
 
562
; Like the task switcher ISR, restore the full CPU state for the first task
563 304 jshamlet
              INIT_NEXT_TASK              ; Reset the next task to task 0
564
              AWAKEN_NEXT_TASK            ; Load task 0's context to system
565 301 jshamlet
 
566
; Create all of the task loops here.
567 304 jshamlet
              INSTANCE_TASK_LOOPS         ; Instantiate the main task loops
568 301 jshamlet
.ENDM
569
;------------------------------------------------------------------------------
570
 
571
;------------------------------------------------------------------------------
572
; Task Loops
573
;------------------------------------------------------------------------------
574
 
575
; INSTANCE_MAIN_LOOP:
576
; These loops represent each task's "main()", and should never "exit".
577
; Each task's func.s file should declare two required functions, TASKn_INIT and
578
; TASKn_EXEC
579
;
580
; Note that the call to the task switch ISR occurs prior to the task's exec
581
;  function to allow every task to finish its setup BEFORE any task begins
582
;  processing.
583
;
584
; Last, the final branch is only taken if the I bit is still NOT set. If it
585
;  somehow gets set, the task will trigger a system panic (which never returns)
586
 
587
; There should be one loop per task. Note that the labels are used in to create
588
;  the table of entry points
589
 
590
.MACRO INSTANCE_TASK_LOOP
591
TASK\@_MAIN:  JSR  TASK\@_INIT
592
_TASK\@_LOOP: CALL_TASK_SW
593
              JSR  TASK\@_EXEC
594
              BNI  _TASK\@_LOOP
595
              CALL_PANIC
596
.ENDM
597
 
598
; INSTANCE_MAIN_LOOPS expands to create the stub main loops for all of the
599
;  tasks based on the template above. There should be one setup per task, hence
600
;  the repeat based on TASK_COUNT. Note that the output labels will be used to
601
;  populate fields in the task parameter table.
602
.MACRO INSTANCE_TASK_LOOPS
603
              .REPEAT TASK_COUNT
604
              INSTANCE_TASK_LOOP
605
              .ENDR
606
.ENDM
607
;------------------------------------------------------------------------------
608
 
609
;------------------------------------------------------------------------------
610
; Software-callable Interrupts
611
;------------------------------------------------------------------------------
612
 
613
; CALL_PANIC executes the same ISR as a memory fault and triggers the shutdown
614
;  sequence. This requires a hard-reset to recover
615
.MACRO CALL_PANIC
616
              INT  0
617
.ENDM
618
 
619
; CALL_TASK_SW executes the same ISR as the pre-emption timer, and allows tasks
620
;  to give up any remaining time
621
.MACRO CALL_TASK_SW
622
              INT  1
623
.ENDM
624
 
625
; Interrupt 2 is reserved for the external interrupt manager. Calling it would
626
;  likely be harmless, but do no real work.
627
 
628
; CALL_SUPV_FNn allow tasks to execute code in an interrupt/supervisor context
629
;  and should be used with caution.
630
.MACRO CALL_SUPV_FN0
631
              INT  3
632
.ENDM
633
 
634
.MACRO CALL_SUPV_FN1
635
              INT  4
636
.ENDM
637
 
638
.MACRO CALL_SUPV_FN2
639
              INT  5
640
.ENDM
641
 
642
.MACRO CALL_SUPV_FN3
643
              INT  6
644
.ENDM
645
 
646
.MACRO CALL_SUPV_FN4
647
              INT  7
648
.ENDM
649
 
650
;------------------------------------------------------------------------------
651
 
652
;------------------------------------------------------------------------------
653
;  CPU Interrupt Control Macros
654
;------------------------------------------------------------------------------
655
.MACRO DISABLE_CPU_INTS
656
              CLR  R0
657
              SMSK
658
.ENDM
659
 
660
.MACRO ENABLE_CPU_INTS
661
              LDI  R0, #CPU_INT_ENABLES
662
              SMSK
663
.ENDM
664
;------------------------------------------------------------------------------
665
 
666
;------------------------------------------------------------------------------
667
; RAM Access Fault Shutdown (CALL_PANIC)
668
;  If a task manages to cause a memory fault, sets default conditions and
669
;   then soft-halts the CPU.
670
;  Note that DISABLE_PREEMPTION_TIMER, SET_FAULT_FLAGS are defined in
671
;   "main_const.s", while PANIC_HALT macro calls each task's PANICn_HALT macro
672
;------------------------------------------------------------------------------
673
 
674
.MACRO PROCESS_RAM_FAULT
675
              DISABLE_CPU_INTS         ; Disable interrupts
676
              DISABLE_PREEMPTION_TIMER ; Disable the task timer
677
              SET_FAULT_FLAGS          ; Copy the faulting task info
678
              EXEC_PANIC_HALT          ; Run any necessary shutdown code
679
_RFLT_HALT:   WAI                      ; Soft-Halt the CPU
680
              JMP  _RFLT_HALT          ; This shouldn't happen, but if it does
681
.ENDM
682
 
683
.MACRO CREATE_PANIC_TASK_BLOCK
684
              LDI  R0, #\@
685
              LDI  R1, #PARAM_TABLE_OFFSET
686
              MUL  R1
687
 
688
              LDA  R2, TASK_PARAMS_PTR + 0  ; Load R3:R2 with the start of the
689
              LDA  R3, TASK_PARAMS_PTR + 1  ;  task parameter region
690
 
691
              ADD  R2                  ; Add [R3:R2] + [R1:R0] -> [R3:R2]
692
              T0X  R2
693
              TX0  R1
694
              ADC  R3
695
              T0X  R3
696
 
697
              ; Update the WQL for the task's panic code so each task isn't
698
              ;  doing this on its own
699
 
700
              LDO  R2, PARAM_WQL_LOW
701
              STA  R0, IO_WRITE_QUAL
702
 
703
              TASK\@_PANIC
704
.ENDM
705
 
706
.MACRO EXEC_PANIC_HALT
707
              .REPEAT TASK_COUNT
708
              CREATE_PANIC_TASK_BLOCK
709
              .ENDR
710
.ENDM
711
 
712
;------------------------------------------------------------------------------
713
 
714
;------------------------------------------------------------------------------
715
; Task Switcher ISR (CALL_TASK_SW)
716
;
717
; Handles switching context between tasks when called.
718
;------------------------------------------------------------------------------
719
 
720
.MACRO SWITCH_TASKS
721 304 jshamlet
              SUSPEND_THIS_TASK
722 301 jshamlet
              AWAKEN_NEXT_TASK
723
.ENDM
724
 
725
;------------------------------------------------------------------------------
726
 
727
;------------------------------------------------------------------------------
728
; External System Interrupt Map & ISR Macros
729
; This code configures the external I/O interrupt manager at startup
730
;------------------------------------------------------------------------------
731
 
732
; Setup the external I/O Interrupt manager by writing the mask registers and
733
;  clearing any pending interrupts. Note that the interrupt enable constants
734
;  are defined in ext_isr_config.s
735
 
736
.MACRO INITIALIZE_IO_INTMGR
737
              CLR  R0                     ; Disable all external interrupts
738
              STA  R0, EXT_INT_MASK
739
 
740
              LDI  R0, #SEMAPHORE_VAL     ; Clear any pending interrupts
741
              STA  R0, EXT_INT_PEND       ;  and do a master acknowledge
742
              STA  R0, EXT_INT_ACK
743
 
744
              LDI  R0, #EXT_INTERRUPT_EN_L; Re-enable the external interrupts
745
              STA  R0, EXT_INT_MASK
746
.ENDM
747
 
748
.MACRO INITIALIZE_IO_INTMGR16
749
              CLR  R0                     ; Disable all external interrupts
750
              STA  R0, EXT_INT16_MASK_L
751
              STA  R0, EXT_INT16_MASK_H
752
 
753
              LDI  R0, #SEMAPHORE_VAL     ; Clear any pending interrupts
754
              STA  R0, EXT_INT16_PEND_L   ;  and do a master acknowledge
755
              STA  R0, EXT_INT16_PEND_H
756
              STA  R0, EXT_INT16_ACK
757
 
758
              LDI  R0, #EXT_INTERRUPT_EN_L; Re-enable the external interrupts
759
              STA  R0, EXT_INT16_MASK_L
760
 
761
              LDI  R0, #EXT_INTERRUPT_EN_H; Re-enable the external interrupts
762
              STA  R0, EXT_INT16_MASK_H
763
.ENDM
764
 
765
; Sets up an individual external interrupt macro. Note that these refer to
766
;  macros defined in ext_isr_config.s
767
 
768
.MACRO PROCESS_EXT_ISR
769
              SET_INT\@_FLAGS
770
 
771
              TX0  R3                  ; When done with the flags, update the
772
              LDI  R1, #EXT_INT\@_BIT  ;  mask clear register with the ext bit
773
              OR   R1                  ;  and restore it to R3. Then, before
774
              T0X  R3                  ;  falling into the next check, make
775
              TX0  R2                  ;  sure to restore the current ints
776
.ENDM
777
 
778
; This code checks the external I/O interrupt manager status and processes the
779
;  flag code for each interrupt source.
780
 
781
.MACRO CHECK_EXTERNAL_IO_INTS
782
_EXT_INT_STRT:PSH  R0
783
              PSH  R1
784
              PSH  R2
785
              PSH  R3
786
 
787
_EXT_INT_LO:  CLR  R0                  ; R3 will be our pending mask clear reg,
788
              T0X  R3                  ;  so clear it here
789
 
790
              LDA  R0, EXT_INT_PEND    ; R2 will be our current pending reg, so
791
              T0X  R2                  ;  load it from the hardware here
792
 
793
_EXT_INT_0:   BTT  0
794
              BRZ  _EXT_INT_1
795
              PROCESS_EXT_ISR
796
 
797
_EXT_INT_1:   BTT  1
798
              BRZ  _EXT_INT_2
799
              PROCESS_EXT_ISR
800
 
801
_EXT_INT_2:   BTT  2
802
              BRZ  _EXT_INT_3
803
              PROCESS_EXT_ISR
804
 
805
_EXT_INT_3:   BTT  3
806
              BRZ  _EXT_INT_4
807
              PROCESS_EXT_ISR
808
 
809
_EXT_INT_4:   BTT  4
810
              BRZ  _EXT_INT_5
811
              PROCESS_EXT_ISR
812
 
813
_EXT_INT_5:   BTT  5
814
              BRZ  _EXT_INT_6
815
              PROCESS_EXT_ISR
816
 
817
_EXT_INT_6:   BTT  6
818
              BRZ  _EXT_INT_7
819
              PROCESS_EXT_ISR
820
 
821
_EXT_INT_7:   BTT  7
822
              BRZ  _EXT_INT_CLR
823
              PROCESS_EXT_ISR
824
 
825
_EXT_INT_CLR: STA  R3, EXT_INT_PEND
826
 
827
              STA  R3, EXT_INT_ACK     ; pending ints and ack the HW
828
 
829
              POP  R3
830
              POP  R2
831
              POP  R1
832
              POP  R0
833
              RTI
834
.ENDM
835
 
836
.MACRO CHECK_EXTERNAL_IO_INTS16
837
_EXT_INT_STRT:PSH  R0
838
              PSH  R1
839
              PSH  R2
840
              PSH  R3
841
 
842
_EXT_INT_LO:  CLR  R0                  ; R3 will be our pending mask clear reg,
843
              T0X  R3                  ;  so clear it here
844
 
845
              LDA  R0, EXT_INT16_PEND_L; R2 will be our current pending reg, so
846
              T0X  R2                  ;  load it from the hardware here
847
 
848
_EXT_INT_0:   BTT  0
849
              BRZ  _EXT_INT_1
850
              PROCESS_EXT_ISR
851
 
852
_EXT_INT_1:   BTT  1
853
              BRZ  _EXT_INT_2
854
              PROCESS_EXT_ISR
855
 
856
_EXT_INT_2:   BTT  2
857
              BRZ  _EXT_INT_3
858
              PROCESS_EXT_ISR
859
 
860
_EXT_INT_3:   BTT  3
861
              BRZ  _EXT_INT_4
862
              PROCESS_EXT_ISR
863
 
864
_EXT_INT_4:   BTT  4
865
              BRZ  _EXT_INT_5
866
              PROCESS_EXT_ISR
867
 
868
_EXT_INT_5:   BTT  5
869
              BRZ  _EXT_INT_6
870
              PROCESS_EXT_ISR
871
 
872
_EXT_INT_6:   BTT  6
873
              BRZ  _EXT_INT_7
874
              PROCESS_EXT_ISR
875
 
876
_EXT_INT_7:   BTT  7
877
              BRZ  _EXT_INT_CLRL
878
              PROCESS_EXT_ISR
879
 
880
_EXT_INT_CLRL:STA  R3, EXT_INT16_PEND_L
881
 
882
_EXT_INT_HI:  CLR  R0
883
              T0X  R3
884
 
885
              LDA  R0, EXT_INT16_PEND_H
886
              T0X  R2
887
 
888
_EXT_INT_8:   BTT  0
889
              BRZ  _EXT_INT_9
890
              PROCESS_EXT_ISR
891
 
892
_EXT_INT_9:   BTT  1
893
              BRZ  _EXT_INT_10
894
              PROCESS_EXT_ISR
895
 
896
_EXT_INT_10:  BTT  2
897
              BRZ  _EXT_INT_11
898
              PROCESS_EXT_ISR
899
 
900
_EXT_INT_11:  BTT  3
901
              BRZ  _EXT_INT_12
902
              PROCESS_EXT_ISR
903
 
904
_EXT_INT_12:  BTT  4
905
              BRZ  _EXT_INT_13
906
              PROCESS_EXT_ISR
907
 
908
_EXT_INT_13:  BTT  5
909
              BRZ  _EXT_INT_14
910
              PROCESS_EXT_ISR
911
 
912
_EXT_INT_14:  BTT  6
913
              BRZ  _EXT_INT_15
914
              PROCESS_EXT_ISR
915
 
916
_EXT_INT_15:  BTT  7
917
              BRZ  _EXT_INT_CLRH
918
              PROCESS_EXT_ISR
919
 
920
_EXT_INT_CLRH:STA  R3, EXT_INT16_PEND_H
921
 
922
_EXT_ACK_HW:  STA  R3, EXT_INT16_ACK     ; pending ints and ack the HW
923
 
924
              POP  R3
925
              POP  R2
926
              POP  R1
927
              POP  R0
928
              RTI
929
.ENDM
930
;------------------------------------------------------------------------------
931
 
932
;------------------------------------------------------------------------------
933
; ISR/Supervisory Mode Functions - Allows tasks to define up to 5 functions
934
;  that will operate in supervisor mode by calling a soft-int.
935
;
936 302 jshamlet
; Note 1: that using these functions requires at least 5 free bytes of stack
937
;
938
; Note 2: Due to assembler limitations, it is actually necessary for each task
939 301 jshamlet
;  to define all 5 sets of these macros, even if not used. These are defined
940
;  in the pattern of TASKx_SPV_FUNCy, where x is the task number and
941
;  y is the function 0-4.
942
;
943 302 jshamlet
; Note 3: Task code for these functions should NOT use RTS or RTI, as this WILL
944 301 jshamlet
;  corrupt their stacks and likely crash the whole system. These are intended
945
;  for operations that are atomic in nature, or that require supervisor perms
946 302 jshamlet
;  due to write access (writing flags/messages to other tasks) Registers will
947
;  be preserved in local system memory and restored prior to entering the stub
948
;  effectively meaning that registers will retain their state through the
949
;  function call. The state of system flags will NOT be retained, however.
950 301 jshamlet
;
951 302 jshamlet
; Note 4: These functions will run to completion (or hang) regardless of the
952 301 jshamlet
;  task timer, as interrupts can't pre-empt each other, so caution should be
953
;  used with them. However, both the internal and external interrupt managers
954
;  will latch incoming interrupts while these are running.
955
;------------------------------------------------------------------------------
956
 
957
; CREATE_SUPV_FUNC creates an individual supervisory task function, which is
958
;  referenced in the ISR table. (EXEC_SUPVn is used in the interrupt table)
959
 
960
.MACRO CREATE_SUPV_FUNC
961 302 jshamlet
EXEC_SUPV\@:  STA  R0, TaskMgr.Temp_R0  ; Copy R0-R3 to local RAM, not stack
962
              STA  R1, TaskMgr.Temp_R1
963
              STA  R2, TaskMgr.Temp_R2
964
              STA  R3, TaskMgr.Temp_R3
965 301 jshamlet
 
966
              REINIT_TASK_TABLE_PTR    ; Setup R3:R2 to point to the task table
967
 
968
              LDO  R2, SUPV_FN\@_ENTRY_HIGH
969
              PSH  R0
970
 
971
              LDO  R2, SUPV_FN\@_ENTRY_LOW
972
              PSH  R0
973
 
974 302 jshamlet
              LDA  R3, TaskMgr.Temp_R3 ; Replace R0-R3 from local RAM so that
975
              LDA  R2, TaskMgr.Temp_R2 ;  the stub has the same register space
976
              LDA  R1, TaskMgr.Temp_R1 ; as a function call - less the flag
977
              LDA  R0, TaskMgr.Temp_R0 ; state, which isn't preserved
978
 
979 301 jshamlet
              RTS                      ; Use RTS to "return" to our jump addr
980
 
981 302 jshamlet
              .REPEAT TASK_COUNT       ; Create a stub for each task. The final
982
              CREATE_F\@_FUNCTION_STUB ;  RTI will be handled in the stubs
983
              .ENDR
984 301 jshamlet
.ENDM
985
 
986
; CREATE_Fn_FUNCTION_STUB creates an entry point that is referenced in the
987
;  TASK_PARAM_TABLE, and is "RTS JMP'ed" to by the code from CREATE_SUPV_FUNC.
988
;  Because RTS was used to reach the code generated in these blocks, a final
989
;  JMP instruction will return to the calling supervisory function without
990
;  disrupting the stack. (These aren't technically subroutines)
991
 
992
.MACRO CREATE_F0_FUNCTION_STUB
993 302 jshamlet
_F0_EXE_S\@:  TASK\@_SUPV_FN0          ; Run the stub code from the task
994
              RTI                      ; Return from the interrupt
995 301 jshamlet
.ENDM
996
 
997
.MACRO CREATE_F1_FUNCTION_STUB
998 302 jshamlet
_F1_EXE_S\@:  TASK\@_SUPV_FN1          ; Run the stub code from the task
999
              RTI                      ; Return from the interrupt
1000 301 jshamlet
.ENDM
1001
 
1002
.MACRO CREATE_F2_FUNCTION_STUB
1003 302 jshamlet
_F2_EXE_S\@:  TASK\@_SUPV_FN2          ; Run the stub code from the task
1004
              RTI                      ; Return from the interrupt
1005 301 jshamlet
.ENDM
1006
 
1007
.MACRO CREATE_F3_FUNCTION_STUB
1008 302 jshamlet
_F3_EXE_S\@:  TASK\@_SUPV_FN3          ; Run the stub code from the task
1009
              RTI                      ; Return from the interrupt
1010 301 jshamlet
.ENDM
1011
 
1012
.MACRO CREATE_F4_FUNCTION_STUB
1013 302 jshamlet
_F4_EXE_S\@:  TASK\@_SUPV_FN4          ; Run the stub code from the task
1014
              RTI                      ; Return from the interrupt
1015 301 jshamlet
.ENDM
1016
 
1017
; INSTANCE_SUPV_FUNCS creates all 5 supervisory function entry points and a set
1018
;  of stub functions for each task and is used to place everything in ROM
1019
.MACRO INSTANCE_SUPV_FUNCS
1020
              .REPEAT 5
1021
              CREATE_SUPV_FUNC
1022
              .ENDR
1023
.ENDM
1024
 
1025
;------------------------------------------------------------------------------

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.