Does PASM offer an indexed or indirect JMP or CALL?
K2
Posts: 693
I need to jump to one of 16 routines, depending on the state of four bits. If I read the manual right, the s and d fields of JMP and CALL instructions are calculated at assembly time. Can MOVS and MOVD still be used on them to do indexed jumps or calls? Can someone steer me to an example of indexed or indirect execution?

Comments
movs myMove,#@table ' base address of table add myMove,index ' add index (0 to n-1) nop ' needed because of pipelining myMove movs myJmp,0-0 ' indirecting nop ' needed because of pipelining myJmp jmp #0-0 ' now go to destination table long @entry1, @entry1, @entry2, @entry3 ' plus 12 more entry pointsYou can use other instructions instead of the NOPs just as long as there's a 1 instruction delay after changing myMove and myJmp.Edit: Oops. Looked like our posts crossed, Mike. Looks like you've just answered my follow-up question, too. Thank you!
mov target,#table 'Init target address with table[0]. add target,index 'Add value in index. jmp target 'Jump to address in target. table jmp #loc0 'Jump table. jmp #loc1 ... jmp #loc14 jmp #loc15 target res 1 index res 1-Phil
movs myjmp,#table 'Init target address with table[0]. add myjmp,index 'Add value in index. nop myjmp jmp 0-0 'Jump to address from table. table long loc0, loc1, ... , loc14, loc15 index res 1-Phil
add myjmp,index 'Add value in index. nop myjmp jmpret $, $+1 'Jump to address from table. table long loc0, loc1, ... , loc14, loc15 index res 1index may be folded into the pipeline slot (nop).-Phil
BTW, grandma is having a problem. For the life of me I can't understand why this isn't working. It's based on Phil's #5 post. Somehow I screwed up his perfectly great idea.
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 VAR long transfer OBJ ser : "Parallax Serial Terminal" PUB start ser.Start(115200) transfer := 0 cognew(@exp, @transfer) repeat ser.Dec(transfer) DAT org 0 mov index, #0 exp mov target, #table 'Init target address with table[0]. add target, index 'Add value in index. jmp target 'Jump to address in target. table jmp #loc0 'Jump table. jmp #loc1 jmp #loc2 jmp #loc3 '******************************************** loc0 mov index, #1 add count, #1 jmp #exp '******************************************** loc1 mov index, #2 jmp #exp '******************************************** loc2 mov index, #3 wrlong count, par jmp #exp '******************************************** loc3 mov index, #0 jmp #exp '******************************************** count res 1 target res 1 index res 1The actual busted code is much bigger. I wrote this pedacito just to pare down the problem to its essentials..
It looks like you added a line ahead of exp, so index never gets initialized.
-Phil
Marko, that's a fascinating optimization you used. In the morning I'm going to look into it further.
The Prop is so unusual that I've been timid to wander too far from the reservation. But it's not like something is going to blow up. Probably.
Anyway, you are all great examples of digging in and figuring things out, a trait I'd love to possess.
Based on all the excellent info from yesterday, I figured I could store the address of a routine in a long (named LOC_RET in this case) and later jump to that long (without #) and it would take me to the routine. Maybe it is doing that, but it seems certain from the diagnostic link (Prop Term) that something goes akimbo very quickly. (Initializing 'count' helped a lot in that regard.
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 VAR long transfer OBJ ser: "Parallax Serial Terminal" PUB s ser.Start(115200) transfer := 0 cognew(@code0, @transfer) repeat ser.Dec(transfer) DAT org 0 '******** TYPE ONE ROUTINES ************** '* code0 mov target, #table '* mov index, #3 '* add target, index '* '< do stuff here > '* mov loc_ret, #ret0 '* jmp target '* ret0 '< more code here > '* '***************************************** code1 mov target, #table '* mov index, #2 '* add target, index '* '< do stuff here > '* mov loc_ret, #ret1 '* jmp target '* ret1 '< more code here > '* '***************************************** code2 mov target, #table '* mov index, #1 '* add target, index '* '< do stuff here > '* mov loc_ret, #ret2 '* jmp target '* ret2 '< more code here > '* '***************************************** code3 mov target, #table '* mov index, #0 '* add target, index '* '< do stuff here > '* mov loc_ret, #ret3 '* jmp target '* ret3 jmp code0 '* '***************************************** '******** TYPE TWO ROUTINES ************** sub0 add count, #1 '* '< do more stuff here > '* jmp loc_ret '* '***************************************** sub1 '< do stuff here > '* jmp loc_ret '* '***************************************** sub2 wrlong count, par '* '< do more stuff here > '* jmp loc_ret '* '***************************************** sub3 '< do stuff here > '* jmp loc_ret '* '***************************************** table jmp #sub0 jmp #sub1 jmp #sub2 jmp #sub3 count long 1 target res 1 index res 1 loc_ret res 1getcmd 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 for cmd == 1 cmd1 ' code here ' -- write result to p1pntr jmp #cmdexitThis is taken from a template I created for PASM code that accepts a command from another cog. It's simple and it always seems to work. I'm an actor. I like simple.
BTW, Thank you!!
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 VAR long transfer OBJ ser: "Parallax Serial Terminal" PUB s ser.Start(115200) transfer := 0 cognew(@goA, @transfer) repeat ser.Dec(transfer) 'just to show activity DAT org 0 goA mov A, indexA add A, #tableA jmp A goX mov X, indexX add X, #tableX jmp X tableA jmp #abc0 jmp #abc1 jmp #abc2 jmp #abc3 tableX jmp #xyz0 jmp #xyz1 jmp #xyz2 jmp #xyz3 abc0 wrlong count, par 'diagnostic add indexA, #1 jmp #goX abc1 add indexA, #1 jmp #goX abc2 add indexA, #1 jmp #goX abc3 mov indexA, #0 jmp #goX xyz0 add count, #1 'diagnostic add indexX, #1 jmp #goA xyz1 add indexX, #1 jmp #goA xyz2 add indexX, #1 jmp #goA xyz3 mov indexX, #0 jmp #goA count long 0 indexA long 0 indexX long 0 A res X reselectrodude
Perhaps if I hadn't been delving into the dangerous territory of JMPs w/o #, I wouldn't have made such a blunder, but who knows? I'll have to ponder that question while I'm assembling miniature log cabins this evening.
Still, the latest version (post 20?) works really well and is less cumbersome than my previous efforts, so perhaps it was worth a few dumb mistakes to get to that point. I've folded the great grandmother approach into the full code (302 lines of asm) and it spins like a top. Now that the needed functionality has been achieved I'm free to tweak it to death.
"i" stands for "immediate," not "indirect." When the bit is set (i.e. JMP #target), the jump location is in the source field of the instruction. When the bit is cleared (i.e. JMP target), the contents of the target location, pointed to by the source field, are used for the jump address.
-Phil