Skipping and CALLs & JMPs
The doc says:
Special SKIPF Branching Rules
Within SKIPF sequences where CALL/CALLPA/CALLPB are used to execute subroutines in which skipping will be suspended until after RET, all CALL/CALLPA/CALLPB immediate (#) branch addresses must be absolute in cases where the instruction after the CALL/CALLPA/CALLPB might be skipped. This is not possible for CALLPA/CALLPB but CALL can use '#\address' syntax to achieve absolute immediate addressing. CALL/CALLPA/CALLPB can all use registers as branch addresses, since they are absolute.
I have done some tests and this is possible. If N instructions are skipped directly after CALLPx {#}D,#S then the first N instructions of the called routine are not executed. Therefore the actual call address is N more than intended and the solution is to subtract N from #S. Note that if two or more skip sequences execute the same CALLPx then N must be the same for all of them.
Other instructions that use the same immediate addressing are affected in the same way and the complete list is as follows:
CALLD D,#S
CALLPA/PB {#}D,#S
DJxx D,#S
IJxx D,#S
TJxx D,#S
Jxxxx #S
JMP #A
CALL #A
CALLA/B #A
CALLD PA/PB/PTRA/PTRB,#A
Test code:
'code to test callpb with immediate 'address when instructions after 'callpb are skipped ' skipf #skip_bits callpb #0,#routine ' nop nop nop nop nop nop nop nop ' ' skip_bits pb '%00000000_0 %11111111 '%00000001_0 %11111110 '%00000011_0 %11111100 '%00000111_0 %11111000 '%00001111_0 %11110000 '%00011111_0 %11100000 '%00111111_0 %11000000 '%01111111_0 %10000000 ' routine bith pb,#0 bith pb,#1 bith pb,#2 bith pb,#3 bith pb,#4 bith pb,#5 bith pb,#6 _ret_ bith pb,#7
EDIT: Info about other instructions added and title changed.
Comments
I suspected as much. It seemed a lot like the similar limitation with a relative branch at the end of a REP block. That also can be computed for correct operation against the REP's looping offset.
Additional instructions are affected. Please see first post for details.
I've done some final tests of the instructions with 20-bit immediate relative A, i.e JMP #A, CALL #A, CALLA/B #A and CALLD PA/PB/PTRA/PTRB,#A. They all behave in an identical way to the other instructions tested earlier. First post updated.
The doc also says:
This addresses my point but I was not sure before precisely what it meant. I think it is best to use absolute addressing for both calls and jumps during skipping, where possible, to guarantee execution at the branch address.
So what does this sentence actually mean? The contrived code examples below should make things clear.
If N instructions are skipped directly after one of these instructions then subtract N from #S. However, if N instructions are not skipped directly after then the actual address branched to will be less than #S and I think the solution is to add N to #S.
Tested with TJZ D,#S but in the end I had to change to TJZ D,S (which always branches straight to address in S) because N was not the same for all the skip sequences.