Tom Hartman says:
...I came up with a method for a "switch" statement, its a little faster than average because it doesn't reload the variable for each case. Each case is 3 clocks if not equal, 4 clocks if equal. Code can appear between cases, but be careful not to alter the contents of w.; Switch, case macros: ; Typical usage: ; #define CONSTANT1 1 ; #define CONSTANT2 2 ; SWITCH_F file_register ; CASE_W CONSTANT1, do_case_1 ; CASE_W CONSTANT2, do_case_2 ; ; --- Or where W is already the variable--- ; SWITCH_W ; CASE_W CONSTANT1, do_case_1 ; CASE_W CONSTANT2, do_case_2 ;-------------- SWITCH_W macro _previous_case set 0 ; W already contains the switch variable endm ;-------------- SWITCH_F macro f_label movf f_label,w ; read the location into w _previous_case set 0 endm ;-------------- CASE_W macro case_const, case_label xorlw case_const^_previous_case btfsc STATUS,Z goto case_label _previous_case set case_const endm ;------------------------------------------------------------------
Rich Leggitt says:
...I thought of a way to cut 'switch' to one instruction, it ain't gonna get any smaller than that :)switch macro retlw $+1 ; return 'return' endm context equ 0x20 movlw task1 ; note task 1 will run first movwf context movlw task2 ; task switcher call $+2 ; make a place for 'switch' to return to goto $-1 ; (i.e. here!) xorwf context,f ; then exchange w and context xorwf context,w xorwf context,f movwf pcl ; and jmp to w task1 blah switch etc switch stuff goto task1 task2 asdf switch zxcz goto task2to which Scott Dattalo commented:
Cool! Now that you write this, I recall someone else (I believe it was Payson) doing something similar. Now that you've got the 'context switching' all confined to one section, you've opened up the possibilities of extending its functionality (without having duplicate code snippets scattered throughout).
- ) You could easily add additional tasks. Cycling through each can be done in a 'round-robin' fashion. For example, after task A then run task B, C,..., N, and back to A.
- ) You could add priorities to the tasks.
- ) With an extra instruction in the 'switch' macro, you could handle multiple pages:
switch macro movlw HIGH($+2) retlw $+1 endm -----------------------If you're using the 12bit core, then you might consider populating the stack with the address of the context switcher. You could do the same with the 14bit core - but chances are you're more likely to need the stack for making calls. (on the 12bit core, the stack is only 2 levels ) Once the stack is filled, then the retlw's will take advantage of stack roll overs.
movlw task1 movwf context movlw task2 setc clrf first_time goto l2 l1 rlf first_time,f btfss first_time,1 l2 call l1 l3 xorlw context,f ; then exchange w and context xorlw context,w xorlw context,f movwf pcl ; and jmp to wfor the 14bit core you could fill the stack:
movlw task1 movwf context movlw task2 setc clrf first_time goto l2 l1 rlf first_time,f btfss first_time,7 l2 call l1 l3 xorlw context,f ; then exchange w and context xorlw context,w xorlw context,f movwf pcl ; and jmp to wI haven't tried this, but once you get the stack 'primed', you can save 4 execution cycles.
see also: