Welcome to the Parallax Discussion Forums, sign-up to participate.

# P2 Tricks, Traps & Differences between P1 (general discussion)

• Posts: 11,711
Thanks, Guys. I've got it now.
• Posts: 15,398
SKIPF and SKIP
Special SKIPF Branching Rules
From the manual...
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.

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.

Today I was testing to see if I could nest subroutines while keeping the skip in place for return.
Here is what I found (only tested in COG)...
* SKIPF fails if the CALL is relative and the next instruction is to be skipped
* SKIP works correctly even if the call is relative (at least my test did)
* SKIPF and SKIP both work correctly if the call is absolute (ie #\label)
* When it works, 2 level nesting works (ie the CALLed routine makes another CALL.

Here is an extract of the code I used
000d8 036 00 C0 07 F6 |               mov       lmm_x, #0
000dc 037 32 18 64 FD |               skipf     #%0000_1100                     ' SKIPF result is $0000_0C31 - WRONG!!! 000e0 038 | ' skip #%0000_1100 ' SKIP result is$0000_FE31 - correct
000e0 038 01 C0 47 F5 |               or        lmm_x, #%0000_0001              ' xxxx xxxx xxx0
000e4 039 1C 00 B0 FD |               call      #sr1                            ' xxxx xxxx xx0x
000e8 03a 04 C0 47 F5 |               or        lmm_x, #%0000_0100              ' xxxx xxxx x1xx skip
000ec 03b 08 C0 47 F5 |               or        lmm_x, #%0000_1000              ' xxxx xxxx 1xxx skip
000f0 03c 10 C0 47 F5 |               or        lmm_x, #%0001_0000              ' xxxx xxx0 xxxx
000f4 03d 20 C0 47 F5 |               or        lmm_x, #%0010_0000              ' xxxx xx0x xxxx
000f8 03e             |
000f8 03e 28 CB AF FD |               call      #_hubHex8
000fc 03f E4 CA AF FD |               call      #_hubTxCR
00100 040 78 CD 8F FD |               jmp       #_hubMonitor
00104 041             |
00104 041             | sr1
00104 041 1C 00 B0 FD |               call      #sr2                            '\ gets skipped if SKIPF and CALL #sr1 is relative
00108 042 01 00 00 FF
0010c 043 00 C0 47 F5 |               or        lmm_x, ##%0010_0000_0000        '/ gets skipped if SKIPF and CALL #sr1 is relative
00110 044 02 00 00 FF
00114 045 00 C0 47 F5 |               or        lmm_x, ##%0100_0000_0000
00118 046 04 00 00 FF
0011c 047 00 C0 47 F5 |               or        lmm_x, ##%1000_0000_0000
00120 048 2D 00 64 FD |               ret
00124 049             |
00124 049             | sr2           or        lmm_x, ##%0001_0000_0000_0000
00124 049 08 00 00 FF
00128 04a 00 C0 47 F5
0012c 04b 10 00 00 FF
00130 04c 00 C0 47 F5 |               or        lmm_x, ##%0010_0000_0000_0000
00134 04d 20 00 00 FF
00138 04e 00 C0 47 F5 |               or        lmm_x, ##%0100_0000_0000_0000
0013c 04f 40 00 00 FF
00140 050 00 C0 47 F5 |               or        lmm_x, ##%1000_0000_0000_0000
00144 051 2D 00 64 FD |               ret
00148 052             |
00148 052             | ' SKIPF result is $0000_0C31 00148 052 | ' SKIP result is$0000_FE31 - correct

000e4 039 41 00 A0 FD |               call      #\sr1                           ' xxxx xxxx xx0x     'SKIPF result is \$0000_FE31 - correct

My Prop boards:
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
• Posts: 7,877
edited 2019-10-08 - 10:55:27
I think I've found a useful trick when using PTRA/B operations. It's a little specialised but I'm sure it can be repurposed in other ways. The trick is the POP'd C/Z flags within the PTRA register are preserved across its operational use.
'===============================================
'Emit string from immediate code in hubRAM
'  input:  (hardware call stack) - hubRAM address of string
' result:  (none)
'scratch:  pb, temp1
'
putsi
mov	temp1, ptra		'preserve existing PTRA
pop	ptra			'address of immediate data following the CALL (includes the calling C/Z flags)
.loop
rdbyte	pb, ptra++	wz	'get next charater, Z sets with null termination
if_nz	call	#putch			'emit character
if_nz	jmp	#.loop
push	ptra			'update return address to instruction following the null character
mov	ptra, temp1		'restore prior PTRA
ret			wcz	'calling C/Z preserved

"We suspect that ALMA will allow us to observe this rare form of CO in many other discs.
By doing that, we can more accurately measure their mass, and determine whether
scientists have systematically been underestimating how much matter they contain."
• Posts: 7,877
edited 2019-10-15 - 00:26:59
I've been getting myself in trouble with concurrent cordic ops. It's quite cool firing it off and coming back later to collect the results ... but, if for example I add in some debug type code, I find I'm breaking things too easy now because all my decimal printing is using the cordic divide operation.

So my first step to tidying this up a little is to at least make the printing routines themselves reliable in this scenario. The trick here is how to know you are getting the newest result - from print's QDIV operation. A little experimenting later and two instructions does it, eg:
emitclkfrq
qdiv	clk_freq, ##1_000_000
pollqmt					'clear old event
.flushloop
getqx	pa				'MHz whole number - at final pipeline result
jnqmt	#.flushloop			'wait for QMT flag - CORDIC pipeline flushed

getqy	temp2				'six decimal places
...


EDIT: PS: I fixed me problem. It was a bug, I wasn't clearing the event flag before using. I keep forgetting that the things that set the event flags, don't reset them.

EDIT2: It's in contrast to the straight through code that assumes the pipeline is empty prior to routine call. Which would be coded like this instead:
emitclkfrq
qdiv	clk_freq, ##1_000_000
getqx	pa				'MHz whole number
getqy	temp2				'six decimal places
...


My first attempt was to check before use, but that immediately annoyed me as bloaty code. eg:
emitclkfrq
pollqmt					'clear old event
.flushloop
getqx	inb
jnqmt	#.flushloop			'wait for QMT flag - CORDIC pipeline flushed

qdiv	clk_freq, ##1_000_000
getqx	pa				'MHz whole number - at final pipeline result
getqy	temp2				'six decimal places
...

"We suspect that ALMA will allow us to observe this rare form of CO in many other discs.
By doing that, we can more accurately measure their mass, and determine whether
scientists have systematically been underestimating how much matter they contain."
• Posts: 15,398
evanh wrote: »
I think I've found a useful trick when using PTRA/B operations. It's a little specialised but I'm sure it can be repurposed in other ways. The trick is the POP'd C/Z flags within the PTRA register are preserved across its operational use.
'===============================================
'Emit string from immediate code in hubRAM
'  input:  (hardware call stack) - hubRAM address of string
' result:  (none)
'scratch:  pb, temp1
'
putsi
mov	temp1, ptra		'preserve existing PTRA
pop	ptra			'address of immediate data following the CALL (includes the calling C/Z flags)
.loop
rdbyte	pb, ptra++	wz	'get next charater, Z sets with null termination
if_nz	call	#putch			'emit character
if_nz	jmp	#.loop
push	ptra			'update return address to instruction following the null character
mov	ptra, temp1		'restore prior PTRA
ret			wcz	'calling C/Z preserved


Interesting. Because PTRA++ only increments the lower 20 bits, and the upper bits remain unchanged.
Certainly a nice way to pass parameters.
My Prop boards:
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com