Skipping and CALLs & JMPs — Parallax Forums

# Skipping and CALLs & JMPs

Posts: 2,045
edited 2023-01-13 00:18

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
'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


• Posts: 14,038

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.

• Posts: 2,045

• Posts: 2,045
edited 2023-01-13 00:11

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:

For non-CALL\CALLPA\CALLPB branches within SKIPF sequences, SKIPF will work through all immediate-relative branches, which are the default for immediate branches within cog/LUT memory. If an absolute-address branch is being used (#\label, register, or RET, for example), you must not skip the first instruction after the branch. This is not a problem with immediate-relative branches, however, since the variable PC stepping works to advantage, by landing the PC at the first instruction of interest at, or beyond, the branch address.

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.

• Posts: 2,045
edited 2023-01-13 13:09

This is not a problem with immediate-relative branches, however, since the variable PC stepping works to advantage, by landing the PC at the first instruction of interest at, or beyond, the branch address.

So what does this sentence actually mean? The contrived code examples below should make things clear.

        jmp     #inc        'a |
jmp     #dec        '  b

dec     sub     x,#1        '| b
sub     y,#2        '| b

'separate jmp for sequences a & b
'wastes 1 long

        jmp     #inc        'a b