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

123457»

Comments

  • Thanks, Guys. I've got it now.
  • 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 
    
    Using absolute addressing works
    000e4 039 41 00 A0 FD |               call      #\sr1                           ' xxxx xxxx xx0x     'SKIPF result is $0000_FE31 - correct
    
    My Prop boards: P8XBlade2, RamBlade, CpuBlade, TriBlade
    Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
    Website: www.clusos.com
    Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
  • evanhevanh 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."
  • evanhevanh 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."
  • 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: P8XBlade2, RamBlade, CpuBlade, TriBlade
    Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
    Website: www.clusos.com
    Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
Sign In or Register to comment.