Shop OBEX P1 Docs P2 Docs Learn Events
Skipping and CALLs & JMPs — Parallax Forums

Skipping and CALLs & JMPs

TonyB_TonyB_ Posts: 2,193
edited 2023-01-13 00:18 in Propeller 2

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

  • evanhevanh Posts: 16,023

    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.

  • TonyB_TonyB_ Posts: 2,193
    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.

  • TonyB_TonyB_ Posts: 2,193
    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
    
    inc     add     x,#1        'a
            add     y,#2        'a
    dec     sub     x,#1        '| b
            sub     y,#2        '| b
    
    'separate jmp for sequences a & b
    'wastes 1 long
    
            jmp     #inc        'a b
    
    inc     add     x,#1        'a |
            add     y,#2        'a |
            sub     x,#1        '| b
            sub     y,#2        '| b
    
    'common jmp for both sequences
    'a jumps to inc, b jumps to inc+2
    'saves 1 long
    
  • TonyB_TonyB_ Posts: 2,193
    edited 2024-04-24 17:49

    @TonyB_ said:
    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

    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.

Sign In or Register to comment.