[PASM] calling the right sub-routine depending on a value

in Propeller 1
I'd like to call one of perhaps 40 different sub-routines based on the value stored in a register...
For instance a "command_ID" value of 1 should cause the CMD_WATCHDOG sub-routine to be called (and in fact this part does work).
The problem is that the code never returns to the point just after :Exec_MODIFIED_JUMP.
I think this is because it's the compiler that deals with the returning address for the CALL opcode, but I'm using MOVS to alter the jump address myself, so perhaps the compiler is actually putting the return address into PLACEHOLDER_ret always.
How can I rewrite this code so that my subroutines know where to return to?
For instance a "command_ID" value of 1 should cause the CMD_WATCHDOG sub-routine to be called (and in fact this part does work).
cmp command_ID, #0 WZ
IF_E MOVS :Exec_MODIFIED_JUMP, #CMD_HARD_RESET
cmp command_ID, #1 WZ
IF_E MOVS :Exec_MODIFIED_JUMP, #CMD_WATCHDOG
'many more of these.....
NOP
:Exec_MODIFIED_JUMP CALL #PLACEHOLDER
'......
PLACEHOLDER NOP
PLACEHOLDER_ret ret
'......
'-----------------------------------------------------------------
' COMMAND SUB-ROUTINES - these are called by self-modifying
' code at ":Exec_MODIFIED_JUMP" above, see comments!
'-----------------------------------------------------------------
'......
'-----------------------------------------------------------------
CMD_WATCHDOG
'debug
mov sertx_byte_out, #"W"
call #Ser_TX_Byte
mov sertx_byte_out, #"D"
call #Ser_TX_Byte
mov sertx_byte_out, LINEFEED
call #Ser_TX_Byte
CMD_WATCHDOG_ret ret
'-----------------------------------------------------------------
'......
The problem is that the code never returns to the point just after :Exec_MODIFIED_JUMP.
I think this is because it's the compiler that deals with the returning address for the CALL opcode, but I'm using MOVS to alter the jump address myself, so perhaps the compiler is actually putting the return address into PLACEHOLDER_ret always.
How can I rewrite this code so that my subroutines know where to return to?
Comments
change this
:Exec_MODIFIED_JUMP CALL #PLACEHOLDER
to:Exec_MODIFIED_JUMP JMPRET return_ptr,#0
(you can get rid of the PLACEHOLDER now. Also don't forget to allocate the return_ptr variable somewhere)Then, instead of RET, do a JMP return_ptr (WITHOUT THE #).
Also, you might be able to reduce the memory usage by using a jump table, like this
MOVS :Exec_MODIFIED_JUMP,#JUMPTABLE ADD :Exec_MODIFIED_JUMP,command_ID NOP :Exec_MODIFIED_JUMP JMPRET return_ptr,0 JUMPTABLE LONG CMD_HARD_RESET, CMD_WATCHDOG ' more of those
rdbyte command_ID,somewhere wz if_nz jmp #not_cmd0 ' Implement command 0 here jmp #somewhere_else not_cmd0 djnz command_ID,#not_cmd1 ' Implement command 1 here jmp #somewhere_else not_cmd1 djnz command_ID,#not_cmd2 ' Implement command 2 here jmp #somewhere_else not_cmd2 djnz command_ID,#not_cmd3 ' Implement command 3 here jmp #somewhere_else ' You get the idea
Fantastic! It works well and is efficient in both time and memory. Thank you very much.
getcmd rdlong t1, par wz ' check for command if_z jmp #getcmd min t1, #0 ' limit range max t1, #4 ' commands + 1 add t1, #jmptable ' prep for jump jmp t1 ' do it jmptable jmp #cmdexit do_cmd1 jmp #cmd1 do_cmd2 jmp #cmd2 do_cmd3 jmp #cmd3 cmdexit mov t1, #0 ' clear old command wrlong t1, par jmp #getcmd ' handler from cmd == 1 cmd1 ' code here ' -- write result to p1pntr jmp #cmdexit