PJV says:
The information I am disclosing and posting here is my personal experience with these "hidden" instructions, and is in no way deemed to be totally correct or complete. Inasmuch as I had no hand in the creation of these instructions, I am only disclosing how I believe them to function. I have not exhaustively tested the performance or results. I have however successfully used them in many applications with excellent results, but any user of them is advised to test the performance for their own application, and use them at their own risk.The performance of the SX Key debugging tool, and the content of the debugging windows may be affected by the use of these instructions, so user beware; what you see may NOT be what you get.
About the SX interrupt.
The SX family has a wonderful interrupt facility which stores the state of the processor system registers, that is the content of W, STATUS, FSR, PC, (and in the SX48/52 also M) registers at the instant of interrupt. It "pushes" them onto shadow register stacks, one associated for each of these system registers. In fact, the shadow registers each are a non-circular stack, two levels deep.
When interrupt is exited through the RETI or RETIW instruction, each of the shadow stacks is "popped", and the original system register's states are restored to the point just prior to interrupt. So interruption and restoration is handled in hardware.
The hidden instructions.
One group of the hidden instructions can modify the content of these shadow stacks, and another group can read the contents of the shadow stacks. Specifically:
"pushW" ($048) will push the content of W onto the Wstack;"pushSTAT" ($049) will push the content of W onto the STATstack;
"pushFSR" ($04A) will push the content of W onto the FSRstack;
"pushPC" ($04B) will push the content of M(4bits) and W(8bits) onto the PCstack.
Conversely,
"popW" ($04C) will pop the upper level of Wstack into W;"popSTAT" ($04D) will pop the upper level of STATstack into W;
"popFSR" ($04E) will pop the upper level of FSRstack into W;
"popPC" ($04F) will pop the upper level of PCstack into M(4bits) and W(8bits).
Executing any of these instructions, I believe, does not affect the STATUS flags.
As these shadow stacks are two levels deep, two consecutive "pushes" or "pops" will affect the second level of the stack, of course through the first level. That is, the first push transfers the first level to the second level, and W to the first level. Similarly, the first pop will bring the first level into W, and the second level into the first level, and the second pop will bring the now first level (this had been the second level) into W. I do not recall for sure, but I believe pops enter zero into the second level in which case two consecutive pops would clear the stack.
"FIFO" ($047) pushes W onto an 8 level circular stack, and rolls the content of the eighth level into W. This is used during debugging to save some data which later needs to be restored, all without the use of the processor's normal "RAM". So executing FIFO 9 times, circulates W through the circular buffer once. There is no "reverse"; FIFO only moves in a "forward" direction, albeit in a circular fashion.There are some other instructions which are probably less interesting to most users, as they are principally used only in the debugging process so I will only mention them here, and not go into detail as I have not used them.
"GetOption" ($001) moves the option register to W"Debug" ($044) sets the SX into debug mode
"OscIO" ($045) swaps the oscillator pin into/outof C
"SetBreak" ($046) sets the breakpoint register
{ed: I've made up names for the above 4 instructions which are probably wrong, but we need something to call them...}
So What's the big deal? Well, of the push/pop/fifo group, firstly one can "pushW" to temporarily store, and later retrieve W without using a RAM location. Very useful for passing a parameter (or two "pushw"s for two parameters) to a subroutine where it is "popped" into W. If a real interrupt occurs in the case when two "pushW"s have been issued, the first one will be lost as the interrupt will push it out of the stack. Single "pushes" are safe during an interrupt, but then the debug process may compromise the pushed contents.
But there is more. One can, while NOT in interrupt, load up the top level of each of the shadow registers for W, STATUS, FSR, PC and then do an RETI or RETW, and voila, start executing another thread with its restored values. Naturally one would need to save the context of the processor prior to activating this other thread.
This is one method I use to have the RTCC interrupt give me a tick every xx microseconds, and I run all other threads timed from that tick by sequentially picking up previously suspended threads of higher priority, and restoring their contexts. This works really well, depending on how creative you want to be. The result is a pretty good performance pre-emptive RTOS for the SX.
So that's about it, experiment to your heart's content, and you'll probably find out things I haven't discovered yet.
Paul Baker says:
I think its worthy to note that if you are using the internal oscillator, the $044 (swap osc pin with w) can be used to gain an additional I/O pin.I think the most useful instruction of the lot is the FIFO instruction, this could be used by a wide variety of communications protocols to buffer data without consuming valuble RAM (it could also be used for a "slow ram" as well).
Note that none of these instructions will have actual names in the compiler. You can't just write pushW and expect SASM or the SXKey to know what that means. The only real way to use these instructions is to DW the numerical value of the instruction. e.g. for PushW, you wite DW $048 which, while it will work, is not the clearest instruction! However, you can create macros that define these values and allow you to write a nicer name:
pushW macro DW $048 endm popW macro DW $04C endm pushSTAT macro DW $049 endm popSTAT macro DW $04D endm pushFSR macro DW $04A endm popFSR macro DW $04E endm pushPC macro DW $04B endm popPC macro DW $04F endm FIFO macro DW $047 endm GetOption macro DW $001 endm Debug macro DW $044 endm OscIO macro DW $045 endm SetBreak macro DW $046 endm