View Full Version : Using the shadow registers behind PAR/CNT/INA/INB

11-05-2006, 06:25 AM
Here is a trick for squeezing a few longs out of your assembly code:

All special registers within the COG ($1F0-$1FF) are backed by shadow ram registers. In the case of the first four registers which are read-only, these shadow registers can be exploited for DJNZ loops and other purposes which rely on the destination·operand only. For example:

·········MOV···· PAR,#16
:loop··· <some code here>
·········DJNZ··· PAR,#:loop

Note that you could do a 'CMP PAR,#1 WZ' to see, for example, if you were on the last loop. When read as the source operand, PAR will always return the boot parameter, regardless of what is in the shadow register. These same rules apply to CNT, INA, and INB.

It's also very clean to use CNT to track CNT targets in timing loops:

········ MOV···· CNT,#5···· '5 makes the initial WAITCNT·fall through immediately
········ ADD···· CNT,CNT

:loop··· WAITCNT·CNT,#100·· 'here you specify your repetitive timing
········ <some code here>
········ JMP···· #:loop
Another nice thing about these shadow registers is that they are all cleared to $00000000 when the cog is booted, giving them a known initial value which can be exploited.

I was scratching my head this afternoon, trying to figure out how I could shave a few longs off a new graphics driver, so that it would fit in the cog. I was already using CTRB (lower bits only, to keep it 'off'), FRQB, and PHSB as general-purpose registers, but needed more. By·getting rid of the general-purpose ram registers being used as counters, and using these 'read-only' registers, instead, I got it packed in!

COG Registers

* Only readable as a Source Register (i.e. MOV DEST,SOURCE)
** Allocated for future use, but not currently implemented


Chip Gracey
Parallax, Inc.

Post Edited (Chip Gracey (Parallax)) : 11/5/2006 12:13:47 AM GMT

Cliff L. Biffle
11-05-2006, 12:56 PM
This is sick, in both the traditional "crazy" sense and the newfangled "cool" sense the kids are using. http://forums.parallax.com/images/smilies/smile.gif

This explains some of the weird behaviors I've been seeing. propasm only allows these registers to be used in S; this is a direct result of some code I was debugging that used PAR in D and got weird, weird results.

Now I know why.

The manual should have enough info about this to give people a clue what might be happening -- but not enough to actually encourage this, because this is pretty far up on the "obscure trick" scale.

11-05-2006, 02:07 PM
Why not?

This is a small scale computing platform. Seems to me, these kinds of things are not only encouraged, but mandatory sometimes.

Over time, we will see more of this and it will make the difference between some projects being average and excellent.

Part of the fun, frankly!

---also kind of educational.

I see your point and it's all good. I'm not being confrontational, just see it from a different perspective that's all.

(looking forward to giving your assembler a try soon BTW!)

11-05-2006, 03:10 PM
I'm working on a pipelined direct digital synthesizer and need a fast way to exit the loop when the main cog wants to change frequency. Is it ok to use the OUTA register for this? eg:

:loop ...
and OUTA,mask wz 'clear the output to allow other cogs access, if mask bit set by control cog, exit
ifz jmp #:loop

:mask long $01000000

when the control cog outputs the mask eg or OUTA,mask the other cogs see this and exit.

Is this ok?

Cheers, Ian

Ian Mitchell