Fun with Cog Special Purpose Registers
hippy
Posts: 1,981
There's a comment in the thread on "what do people want for the Prop II" from Chip about executing code held in a Cog's Special Purpose Registers ($1F0-$1FF) which I hadn't paid much attention to or appreciated before, but is quite interesting. Maybe it's not news to everyone but some people may find it useful or at least interesting as well. If not, just ignore this post 
Providing nothing is written to the SPR which affects the physical configuration of the Cog ( for example writing DIRA with non-zero will create an output pin ), code can be written and then executed. What's executed is whatever was written, not what would be read if that SPR were used as a source register in an instruction. That makes $1F0 to $1F5 available for use.
Code has to be moved into the SPR because it cannot be loaded as a part of CogNew which is a shame, but it may have some use somewhere. The following runs in SPR and increments a long in Hub memory ...
Note how the rdlong at $1F0 is executed as a rdlong not the instruction the value passed in as PAR represents, yet when PAR is used in that rdlong the actual PAR register is used to get the address which should be read.
Post Edited (hippy) : 3/11/2008 5:20:30 AM GMT

Providing nothing is written to the SPR which affects the physical configuration of the Cog ( for example writing DIRA with non-zero will create an output pin ), code can be written and then executed. What's executed is whatever was written, not what would be read if that SPR were used as a source register in an instruction. That makes $1F0 to $1F5 available for use.
Code has to be moved into the SPR because it cannot be loaded as a part of CogNew which is a shame, but it may have some use somewhere. The following runs in SPR and increments a long in Hub memory ...
CON
_CLKMODE = XTAL1 + PLL16x
_XINFREQ = 5_000_000
TV_PIN = 12
OBJ
tv : "TV_Text"
VAR
long counter
PUB Main
tv.Start( TV_PIN )
CogNew( @IncHub, @counter )
repeat
tv.Out( 1 )
tv.Dec( counter )
DAT
IncHub org $000
mov $1F0,x1F0
mov $1F1,x1F1
mov $1F2,x1F2
mov $1F3,x1F3
mov $1F4,x1F4
mov $1F5,x1F5
jmp #$1F0
tmp long 0
x1F0 rdlong tmp,PAR ' $1F0 - PAR
x1F1 add tmp,#1 ' $1F1 - CNT
x1F2 wrlong tmp,PAR ' $1F2 - INA
x1F3 nop ' $1F3 - INB
x1F4 nop ' $1F4 - OUTA
x1F5 jmp #$1F0 ' $1F5 - OUTB
Note how the rdlong at $1F0 is executed as a rdlong not the instruction the value passed in as PAR represents, yet when PAR is used in that rdlong the actual PAR register is used to get the address which should be read.
Post Edited (hippy) : 3/11/2008 5:20:30 AM GMT

Comments
Very popular are things as:
MOV INA, NN
....
DJNZ INA,...
Note that this double use affects the 6 "Read Only Registsters" (which obviously is a mis-nomer) only: PAR, CNT, INA, INB, PHSA, PHSB.
Here's a 'zero-footprint' LMM implementation which runs entirely in SPR ( the loading code can be zeroed as part of Cog initialisation ). Once LMM is running the LMM code has unrestricted use of all 496 registers, SPR and I/O ( except on Prop II because OUTB is used ).
Being kernel-less means jumps, calls and loads of values over $1FF have to be handled somewhat convolutedly in the LMM itself so it's not necessarily practical but could have possibilities.
This uses LMM to increment the long at $7FFC ...
CON _CLKMODE = XTAL1 + PLL16x _XINFREQ = 5_000_000 TV_PIN = 12 OBJ tv : "TV_Text" PUB Main tv.Start( TV_PIN ) CogNew( @RunLmm, @Lmm ) repeat tv.Out( 1 ) tv.Dec( long[noparse][[/noparse] $7FFC ] ) DAT Lmm mov $000,PAR add $000,#Lmm_Loop-Lmm mov $001,#$7F shl $001,#8 or $001,#$FC Lmm_Loop rdlong $002,$001 add $002,#1 wrlong $002,$001 mov $1F5,$000 DAT RunLmm org $000 mov $1F0,x1F0 mov $1F1,x1F1 mov $1F2,x1F2 mov $1F3,x1F3 mov $1F5,PAR jmp #$1F0 x1F0 rdlong $1F2,$1F5 ' $1F0 - PAR - Fetch x1F1 add $1F5,#4 ' $1F1 - CNT - Increment LMM PC x1F2 nop ' $1F2 - INA - Execute LMM opcode x1F3 jmp #$1F0 ' $1F3 - INB - Repeat x1F4 res 1 ' $1F4 - OUTA - Used for I/O control x1F5 res 1 ' $1F5 - OUTB - LMM PC